From a025e0478ffea2d1cc1441bfff8a2bbbbae93399 Mon Sep 17 00:00:00 2001 From: donovan Date: Wed, 11 Jun 2008 13:07:46 -0700 Subject: [PATCH] Remove .svn directories --- .svn/all-wcprops | 17 - .svn/entries | 58 -- .svn/format | 1 - .svn/text-base/README.svn-base | 66 -- .svn/text-base/setup.py.svn-base | 28 - eventlet/.svn/all-wcprops | 245 ------- eventlet/.svn/dir-prop-base | 9 - eventlet/.svn/entries | 541 -------------- eventlet/.svn/format | 1 - eventlet/.svn/prop-base/__init__.py.svn-base | 5 - eventlet/.svn/prop-base/api.py.svn-base | 5 - eventlet/.svn/prop-base/api_test.py.svn-base | 5 - eventlet/.svn/prop-base/backdoor.py.svn-base | 5 - eventlet/.svn/prop-base/channel.py.svn-base | 5 - eventlet/.svn/prop-base/coros.py.svn-base | 5 - .../.svn/prop-base/coros_test.py.svn-base | 5 - eventlet/.svn/prop-base/greenlib.py.svn-base | 5 - eventlet/.svn/prop-base/httpc.py.svn-base | 5 - eventlet/.svn/prop-base/httpd.py.svn-base | 5 - .../.svn/prop-base/httpd_test.py.svn-base | 5 - eventlet/.svn/prop-base/httpdate.py.svn-base | 5 - eventlet/.svn/prop-base/jsonhttp.py.svn-base | 5 - eventlet/.svn/prop-base/kqueuehub.py.svn-base | 5 - eventlet/.svn/prop-base/logutil.py.svn-base | 5 - eventlet/.svn/prop-base/pollhub.py.svn-base | 5 - eventlet/.svn/prop-base/pools.py.svn-base | 5 - .../.svn/prop-base/pools_test.py.svn-base | 5 - eventlet/.svn/prop-base/processes.py.svn-base | 5 - .../.svn/prop-base/processes_test.py.svn-base | 5 - .../.svn/prop-base/pylibsupport.py.svn-base | 5 - eventlet/.svn/prop-base/runloop.py.svn-base | 5 - .../.svn/prop-base/runloop_test.py.svn-base | 5 - eventlet/.svn/prop-base/selecthub.py.svn-base | 5 - .../prop-base/stacklesssupport.py.svn-base | 5 - eventlet/.svn/prop-base/tests.py.svn-base | 5 - eventlet/.svn/prop-base/timer.py.svn-base | 5 - .../.svn/prop-base/timer_test.py.svn-base | 5 - eventlet/.svn/prop-base/tls.py.svn-base | 5 - .../.svn/prop-base/twistedsupport.py.svn-base | 5 - eventlet/.svn/prop-base/util.py.svn-base | 5 - eventlet/.svn/prop-base/wrappedfd.py.svn-base | 5 - eventlet/.svn/prop-base/wsgi.py.svn-base | 5 - eventlet/.svn/text-base/__init__.py.svn-base | 24 - eventlet/.svn/text-base/api.py.svn-base | 309 -------- eventlet/.svn/text-base/api_test.py.svn-base | 164 ----- eventlet/.svn/text-base/backdoor.py.svn-base | 85 --- eventlet/.svn/text-base/channel.py.svn-base | 98 --- eventlet/.svn/text-base/coros.py.svn-base | 457 ------------ .../.svn/text-base/coros_test.py.svn-base | 300 -------- eventlet/.svn/text-base/db_pool.py.svn-base | 220 ------ .../.svn/text-base/db_pool_test.py.svn-base | 309 -------- eventlet/.svn/text-base/greenlib.py.svn-base | 331 --------- eventlet/.svn/text-base/httpc.py.svn-base | 597 --------------- .../.svn/text-base/httpc_test.py.svn-base | 396 ---------- eventlet/.svn/text-base/httpd.py.svn-base | 584 --------------- .../.svn/text-base/httpd_test.py.svn-base | 207 ------ eventlet/.svn/text-base/httpdate.py.svn-base | 39 - eventlet/.svn/text-base/jsonhttp.py.svn-base | 40 - eventlet/.svn/text-base/kqueuehub.py.svn-base | 219 ------ eventlet/.svn/text-base/logutil.py.svn-base | 112 --- eventlet/.svn/text-base/pollhub.py.svn-base | 189 ----- eventlet/.svn/text-base/pools.py.svn-base | 184 ----- .../.svn/text-base/pools_test.py.svn-base | 179 ----- eventlet/.svn/text-base/processes.py.svn-base | 141 ---- .../.svn/text-base/processes_test.py.svn-base | 134 ---- .../.svn/text-base/pylibsupport.py.svn-base | 42 -- eventlet/.svn/text-base/runloop.py.svn-base | 228 ------ .../.svn/text-base/runloop_test.py.svn-base | 157 ---- eventlet/.svn/text-base/saranwrap.py.svn-base | 685 ------------------ .../.svn/text-base/saranwrap_test.py.svn-base | 316 -------- eventlet/.svn/text-base/selecthub.py.svn-base | 173 ----- .../text-base/stacklesssupport.py.svn-base | 110 --- eventlet/.svn/text-base/tests.py.svn-base | 89 --- eventlet/.svn/text-base/timer.py.svn-base | 83 --- .../.svn/text-base/timer_test.py.svn-base | 66 -- eventlet/.svn/text-base/tls.py.svn-base | 57 -- eventlet/.svn/text-base/tpool.py.svn-base | 123 ---- .../.svn/text-base/tpool_test.py.svn-base | 70 -- .../.svn/text-base/twistedsupport.py.svn-base | 134 ---- eventlet/.svn/text-base/util.py.svn-base | 214 ------ eventlet/.svn/text-base/wrappedfd.py.svn-base | 284 -------- eventlet/.svn/text-base/wsgi.py.svn-base | 219 ------ eventlet/.svn/tmp/tempfile.2.tmp | 584 --------------- examples/.svn/all-wcprops | 17 - examples/.svn/entries | 54 -- examples/.svn/format | 1 - .../.svn/prop-base/echoserver.py.svn-base | 5 - .../.svn/prop-base/webcrawler.py.svn-base | 5 - .../.svn/text-base/echoserver.py.svn-base | 52 -- .../.svn/text-base/webcrawler.py.svn-base | 55 -- 90 files changed, 10272 deletions(-) delete mode 100644 .svn/all-wcprops delete mode 100644 .svn/entries delete mode 100644 .svn/format delete mode 100644 .svn/text-base/README.svn-base delete mode 100644 .svn/text-base/setup.py.svn-base delete mode 100644 eventlet/.svn/all-wcprops delete mode 100644 eventlet/.svn/dir-prop-base delete mode 100644 eventlet/.svn/entries delete mode 100644 eventlet/.svn/format delete mode 100644 eventlet/.svn/prop-base/__init__.py.svn-base delete mode 100644 eventlet/.svn/prop-base/api.py.svn-base delete mode 100644 eventlet/.svn/prop-base/api_test.py.svn-base delete mode 100644 eventlet/.svn/prop-base/backdoor.py.svn-base delete mode 100644 eventlet/.svn/prop-base/channel.py.svn-base delete mode 100644 eventlet/.svn/prop-base/coros.py.svn-base delete mode 100644 eventlet/.svn/prop-base/coros_test.py.svn-base delete mode 100644 eventlet/.svn/prop-base/greenlib.py.svn-base delete mode 100644 eventlet/.svn/prop-base/httpc.py.svn-base delete mode 100644 eventlet/.svn/prop-base/httpd.py.svn-base delete mode 100644 eventlet/.svn/prop-base/httpd_test.py.svn-base delete mode 100644 eventlet/.svn/prop-base/httpdate.py.svn-base delete mode 100644 eventlet/.svn/prop-base/jsonhttp.py.svn-base delete mode 100644 eventlet/.svn/prop-base/kqueuehub.py.svn-base delete mode 100644 eventlet/.svn/prop-base/logutil.py.svn-base delete mode 100644 eventlet/.svn/prop-base/pollhub.py.svn-base delete mode 100644 eventlet/.svn/prop-base/pools.py.svn-base delete mode 100644 eventlet/.svn/prop-base/pools_test.py.svn-base delete mode 100644 eventlet/.svn/prop-base/processes.py.svn-base delete mode 100644 eventlet/.svn/prop-base/processes_test.py.svn-base delete mode 100644 eventlet/.svn/prop-base/pylibsupport.py.svn-base delete mode 100644 eventlet/.svn/prop-base/runloop.py.svn-base delete mode 100644 eventlet/.svn/prop-base/runloop_test.py.svn-base delete mode 100644 eventlet/.svn/prop-base/selecthub.py.svn-base delete mode 100644 eventlet/.svn/prop-base/stacklesssupport.py.svn-base delete mode 100644 eventlet/.svn/prop-base/tests.py.svn-base delete mode 100644 eventlet/.svn/prop-base/timer.py.svn-base delete mode 100644 eventlet/.svn/prop-base/timer_test.py.svn-base delete mode 100644 eventlet/.svn/prop-base/tls.py.svn-base delete mode 100644 eventlet/.svn/prop-base/twistedsupport.py.svn-base delete mode 100644 eventlet/.svn/prop-base/util.py.svn-base delete mode 100644 eventlet/.svn/prop-base/wrappedfd.py.svn-base delete mode 100644 eventlet/.svn/prop-base/wsgi.py.svn-base delete mode 100644 eventlet/.svn/text-base/__init__.py.svn-base delete mode 100644 eventlet/.svn/text-base/api.py.svn-base delete mode 100644 eventlet/.svn/text-base/api_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/backdoor.py.svn-base delete mode 100644 eventlet/.svn/text-base/channel.py.svn-base delete mode 100644 eventlet/.svn/text-base/coros.py.svn-base delete mode 100644 eventlet/.svn/text-base/coros_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/db_pool.py.svn-base delete mode 100644 eventlet/.svn/text-base/db_pool_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/greenlib.py.svn-base delete mode 100644 eventlet/.svn/text-base/httpc.py.svn-base delete mode 100644 eventlet/.svn/text-base/httpc_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/httpd.py.svn-base delete mode 100644 eventlet/.svn/text-base/httpd_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/httpdate.py.svn-base delete mode 100644 eventlet/.svn/text-base/jsonhttp.py.svn-base delete mode 100644 eventlet/.svn/text-base/kqueuehub.py.svn-base delete mode 100644 eventlet/.svn/text-base/logutil.py.svn-base delete mode 100644 eventlet/.svn/text-base/pollhub.py.svn-base delete mode 100644 eventlet/.svn/text-base/pools.py.svn-base delete mode 100644 eventlet/.svn/text-base/pools_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/processes.py.svn-base delete mode 100644 eventlet/.svn/text-base/processes_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/pylibsupport.py.svn-base delete mode 100644 eventlet/.svn/text-base/runloop.py.svn-base delete mode 100644 eventlet/.svn/text-base/runloop_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/saranwrap.py.svn-base delete mode 100644 eventlet/.svn/text-base/saranwrap_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/selecthub.py.svn-base delete mode 100644 eventlet/.svn/text-base/stacklesssupport.py.svn-base delete mode 100644 eventlet/.svn/text-base/tests.py.svn-base delete mode 100644 eventlet/.svn/text-base/timer.py.svn-base delete mode 100644 eventlet/.svn/text-base/timer_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/tls.py.svn-base delete mode 100644 eventlet/.svn/text-base/tpool.py.svn-base delete mode 100644 eventlet/.svn/text-base/tpool_test.py.svn-base delete mode 100644 eventlet/.svn/text-base/twistedsupport.py.svn-base delete mode 100644 eventlet/.svn/text-base/util.py.svn-base delete mode 100644 eventlet/.svn/text-base/wrappedfd.py.svn-base delete mode 100644 eventlet/.svn/text-base/wsgi.py.svn-base delete mode 100644 eventlet/.svn/tmp/tempfile.2.tmp delete mode 100644 examples/.svn/all-wcprops delete mode 100644 examples/.svn/entries delete mode 100644 examples/.svn/format delete mode 100644 examples/.svn/prop-base/echoserver.py.svn-base delete mode 100644 examples/.svn/prop-base/webcrawler.py.svn-base delete mode 100644 examples/.svn/text-base/echoserver.py.svn-base delete mode 100644 examples/.svn/text-base/webcrawler.py.svn-base diff --git a/.svn/all-wcprops b/.svn/all-wcprops deleted file mode 100644 index 57eb68b..0000000 --- a/.svn/all-wcprops +++ /dev/null @@ -1,17 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 32 -/svn/eventlet/!svn/ver/100/trunk -END -setup.py -K 25 -svn:wc:ra_dav:version-url -V 40 -/svn/eventlet/!svn/ver/83/trunk/setup.py -END -README -K 25 -svn:wc:ra_dav:version-url -V 38 -/svn/eventlet/!svn/ver/83/trunk/README -END diff --git a/.svn/entries b/.svn/entries deleted file mode 100644 index f8865c0..0000000 --- a/.svn/entries +++ /dev/null @@ -1,58 +0,0 @@ -8 - -dir -100 -https://svn.secondlife.com/svn/eventlet/trunk -https://svn.secondlife.com/svn/eventlet - - - -2008-03-05T09:26:30.084594Z -100 -which.linden - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -cde37729-5338-0410-b9e2-c56166a61366 - -eventlet -dir - -setup.py -file - - - - -2008-02-20T19:57:15.000000Z -82a68910db8376655db41f89b3829524 -2008-01-28T22:21:28.111792Z -83 -which.linden - -README -file - - - - -2008-02-20T19:57:15.000000Z -8d9257b4ae3863579afebab7b38fa8ea -2008-01-28T22:21:28.111792Z -83 -which.linden - -examples -dir - diff --git a/.svn/format b/.svn/format deleted file mode 100644 index 45a4fb7..0000000 --- a/.svn/format +++ /dev/null @@ -1 +0,0 @@ -8 diff --git a/.svn/text-base/README.svn-base b/.svn/text-base/README.svn-base deleted file mode 100644 index 18094ae..0000000 --- a/.svn/text-base/README.svn-base +++ /dev/null @@ -1,66 +0,0 @@ -= eventlet = - -Eventlet is a networking library written in Python. It achieves high -scalability by using non-blocking io while at the same time retaining -high programmer usability by using coroutines to make the non-blocking -io operations appear blocking at the source code level. - -The wiki at http://wiki.secondlife.com/wiki/Eventlet is likely to be a -more current source of information than this README. Questions, -patches, and general discussion go to the eventlet mailing list: -https://lists.secondlife.com/cgi-bin/mailman/listinfo/eventletdev - -== requirements === - -Eventlet runs on Python version 2.3 or greater, with the following dependenceis: -* [http://cheeseshop.python.org/pypi/greenlet -* (if running python versions < 2.4) collections.py from the 2.4 distribution or later - -== limitations == - -* Sorely lacking in documentation -* Not enough test coverage -- the goal is 100%, but we are not there yet. -* Eventlet does not currently run on stackless using tasklets, though -it is a goal to do so in the future. -* The SSL client does not properly connect to the SSL server, though -both client and server interoperate with other SSL implementations -(e.g. curl and apache). - -== getting started == - -% python ->>> from eventlet import api ->>> help(api) - -Also, look at the examples in the examples directory. - -== eventlet history == - -eventlet began life as Donovan Preston was talking to Bob Ippolito -about coroutine-based non-blocking networking frameworks in -Python. Most non-blocking frameworks require you to run the "main -loop" in order to perform all network operations, but Donovan wondered -if a library written using a trampolining style could get away with -transparently running the main loop any time i/o was required, -stopping the main loop once no more i/o was scheduled. Bob spent a few -days during PyCon 2005 writing a proof-of-concept. He named it -eventlet, after the coroutine implementation it used, -[[greenlet]]. Donovan began using eventlet as a light-weight network -library for his spare-time project Pavel, and also began writing some -unittests. - -* http://svn.red-bean.com/bob/eventlet/trunk/ -* http://soundfarmer.com/Pavel/trunk/ - -When Donovan started at Linden Lab in May of 2006, he added eventlet -as an svn external in the indra/lib/python directory, to be a -dependency of the yet-to-be-named [[backbone]] project (at the time, -it was named restserv). However, including eventlet as an svn external -meant that any time the externally hosted project had hosting issues, -Linden developers were not able to perform svn updates. Thus, the -eventlet source was imported into the linden source tree at the same -location, and became a fork. - -Bob Ippolito has ceased working on eventlet and has stated his desire -for Linden to take its fork forward to the open source world as "the" -eventlet. diff --git a/.svn/text-base/setup.py.svn-base b/.svn/text-base/setup.py.svn-base deleted file mode 100644 index dd5999c..0000000 --- a/.svn/text-base/setup.py.svn-base +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python - -from setuptools import setup - -setup( - name='eventlet', - version='0.2', - description='Coroutine-based networking library', - author='Linden Lab', - author_email='eventletdev@lists.secondlife.com', - url='http://wiki.secondlife.com/wiki/Eventlet', - packages=['eventlet'], - install_requires=['greenlet'], - long_description=""" - Eventlet is a networking library written in Python. It achieves - high scalability by using non-blocking io while at the same time - retaining high programmer usability by using coroutines to make - the non-blocking io operations appear blocking at the source code - level.""", - classifiers=[ - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Internet", - "Topic :: Software Development :: Libraries :: Python Modules", - "Intended Audience :: Developers", - "Development Status :: 4 - Beta"] - ) - diff --git a/eventlet/.svn/all-wcprops b/eventlet/.svn/all-wcprops deleted file mode 100644 index bb8cae0..0000000 --- a/eventlet/.svn/all-wcprops +++ /dev/null @@ -1,245 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 41 -/svn/eventlet/!svn/ver/100/trunk/eventlet -END -stacklesssupport.py -K 25 -svn:wc:ra_dav:version-url -V 59 -/svn/eventlet/!svn/ver/3/trunk/eventlet/stacklesssupport.py -END -pools_test.py -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/eventlet/!svn/ver/3/trunk/eventlet/pools_test.py -END -pools.py -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/eventlet/!svn/ver/101/trunk/eventlet/pools.py -END -tpool_test.py -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/eventlet/!svn/ver/86/trunk/eventlet/tpool_test.py -END -saranwrap_test.py -K 25 -svn:wc:ra_dav:version-url -V 58 -/svn/eventlet/!svn/ver/80/trunk/eventlet/saranwrap_test.py -END -runloop_test.py -K 25 -svn:wc:ra_dav:version-url -V 56 -/svn/eventlet/!svn/ver/68/trunk/eventlet/runloop_test.py -END -saranwrap.py -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/eventlet/!svn/ver/100/trunk/eventlet/saranwrap.py -END -runloop.py -K 25 -svn:wc:ra_dav:version-url -V 51 -/svn/eventlet/!svn/ver/91/trunk/eventlet/runloop.py -END -kqueuehub.py -K 25 -svn:wc:ra_dav:version-url -V 52 -/svn/eventlet/!svn/ver/3/trunk/eventlet/kqueuehub.py -END -__init__.py -K 25 -svn:wc:ra_dav:version-url -V 51 -/svn/eventlet/!svn/ver/3/trunk/eventlet/__init__.py -END -tests.py -K 25 -svn:wc:ra_dav:version-url -V 49 -/svn/eventlet/!svn/ver/88/trunk/eventlet/tests.py -END -tls.py -K 25 -svn:wc:ra_dav:version-url -V 46 -/svn/eventlet/!svn/ver/3/trunk/eventlet/tls.py -END -pollhub.py -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/eventlet/!svn/ver/3/trunk/eventlet/pollhub.py -END -api.py -K 25 -svn:wc:ra_dav:version-url -V 47 -/svn/eventlet/!svn/ver/37/trunk/eventlet/api.py -END -wsgi.py -K 25 -svn:wc:ra_dav:version-url -V 47 -/svn/eventlet/!svn/ver/3/trunk/eventlet/wsgi.py -END -pylibsupport.py -K 25 -svn:wc:ra_dav:version-url -V 55 -/svn/eventlet/!svn/ver/3/trunk/eventlet/pylibsupport.py -END -wrappedfd.py -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/eventlet/!svn/ver/87/trunk/eventlet/wrappedfd.py -END -util.py -K 25 -svn:wc:ra_dav:version-url -V 47 -/svn/eventlet/!svn/ver/3/trunk/eventlet/util.py -END -selecthub.py -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/eventlet/!svn/ver/16/trunk/eventlet/selecthub.py -END -timer_test.py -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/eventlet/!svn/ver/68/trunk/eventlet/timer_test.py -END -timer.py -K 25 -svn:wc:ra_dav:version-url -V 49 -/svn/eventlet/!svn/ver/92/trunk/eventlet/timer.py -END -twistedsupport.py -K 25 -svn:wc:ra_dav:version-url -V 57 -/svn/eventlet/!svn/ver/3/trunk/eventlet/twistedsupport.py -END -httpc_test.py -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/eventlet/!svn/ver/70/trunk/eventlet/httpc_test.py -END -httpc.py -K 25 -svn:wc:ra_dav:version-url -V 49 -/svn/eventlet/!svn/ver/95/trunk/eventlet/httpc.py -END -httpd_test.py -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/eventlet/!svn/ver/97/trunk/eventlet/httpd_test.py -END -coros_test.py -K 25 -svn:wc:ra_dav:version-url -V 55 -/svn/eventlet/!svn/ver/101/trunk/eventlet/coros_test.py -END -tpool.py -K 25 -svn:wc:ra_dav:version-url -V 49 -/svn/eventlet/!svn/ver/93/trunk/eventlet/tpool.py -END -processes_test.py -K 25 -svn:wc:ra_dav:version-url -V 57 -/svn/eventlet/!svn/ver/3/trunk/eventlet/processes_test.py -END -processes.py -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/eventlet/!svn/ver/16/trunk/eventlet/processes.py -END -api_test.py -K 25 -svn:wc:ra_dav:version-url -V 51 -/svn/eventlet/!svn/ver/3/trunk/eventlet/api_test.py -END -channel.py -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/eventlet/!svn/ver/3/trunk/eventlet/channel.py -END -jsonhttp.py -K 25 -svn:wc:ra_dav:version-url -V 52 -/svn/eventlet/!svn/ver/75/trunk/eventlet/jsonhttp.py -END -db_pool_test.py -K 25 -svn:wc:ra_dav:version-url -V 56 -/svn/eventlet/!svn/ver/85/trunk/eventlet/db_pool_test.py -END -httpdate.py -K 25 -svn:wc:ra_dav:version-url -V 51 -/svn/eventlet/!svn/ver/3/trunk/eventlet/httpdate.py -END -db_pool.py -K 25 -svn:wc:ra_dav:version-url -V 51 -/svn/eventlet/!svn/ver/93/trunk/eventlet/db_pool.py -END -logutil.py -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/eventlet/!svn/ver/3/trunk/eventlet/logutil.py -END -httpd.py -K 25 -svn:wc:ra_dav:version-url -V 49 -/svn/eventlet/!svn/ver/97/trunk/eventlet/httpd.py -END -backdoor.py -K 25 -svn:wc:ra_dav:version-url -V 51 -/svn/eventlet/!svn/ver/3/trunk/eventlet/backdoor.py -END -coros.py -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/eventlet/!svn/ver/101/trunk/eventlet/coros.py -END -greenlib.py -K 25 -svn:wc:ra_dav:version-url -V 52 -/svn/eventlet/!svn/ver/96/trunk/eventlet/greenlib.py -END diff --git a/eventlet/.svn/dir-prop-base b/eventlet/.svn/dir-prop-base deleted file mode 100644 index 96ae2a7..0000000 --- a/eventlet/.svn/dir-prop-base +++ /dev/null @@ -1,9 +0,0 @@ -K 10 -svn:ignore -V 16 -*.pyc -*~ - -*.tmp - -END diff --git a/eventlet/.svn/entries b/eventlet/.svn/entries deleted file mode 100644 index c9b2174..0000000 --- a/eventlet/.svn/entries +++ /dev/null @@ -1,541 +0,0 @@ -8 - -dir -100 -https://svn.secondlife.com/svn/eventlet/trunk/eventlet -https://svn.secondlife.com/svn/eventlet - - - -2008-03-05T09:26:30.084594Z -100 -which.linden -has-props - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -cde37729-5338-0410-b9e2-c56166a61366 - -stacklesssupport.py -file - - - - -2008-02-20T19:57:15.000000Z -6c51017e724b0fadba816ed73de7648f -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -pools_test.py -file - - - - -2008-02-20T19:57:15.000000Z -3835ff82a7af6edc7c09d276c67cd5db -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -pools.py -file -101 - - - -2008-03-08T01:16:18.000000Z -3734d5d23e28b08aaf0ec7df1f97b164 -2008-03-11T02:26:32.072967Z -101 -which.linden -has-props - -tpool_test.py -file - - - - -2008-02-20T19:57:15.000000Z -c5cb15c24b12acc0bcc14694a74de48b -2008-02-05T01:39:10.353080Z -86 -which.linden - -saranwrap_test.py -file - - - - -2008-02-20T19:57:15.000000Z -f99f25b424a2fc6780dfa0ab6a69eba4 -2008-01-24T00:14:38.439330Z -80 -which.linden - -runloop_test.py -file - - - - -2008-02-20T19:57:15.000000Z -e724370d70719da2834273b0bd5e84fc -2007-12-13T19:39:23.000239Z -68 -donovan.linden -has-props - -saranwrap.py -file - - - - -2008-03-05T09:22:18.000000Z -9b5f20eb03a7d45981c5d32e944008e4 -2008-03-05T09:26:30.084594Z -100 -which.linden - -runloop.py -file - - - - -2008-02-20T19:57:15.000000Z -0313cf6b7844ced258f7f6918d923435 -2008-02-19T06:10:56.251879Z -91 -which.linden -has-props - -kqueuehub.py -file - - - - -2008-02-20T19:57:15.000000Z -c68edf1618f20648e93e0a5a9b841b42 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -__init__.py -file - - - - -2008-02-20T19:57:15.000000Z -d2fd03ba7a2f3c38b210f598e9e0f52e -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -tests.py -file - - - - -2008-02-20T19:57:15.000000Z -7e2f8dcedb9825b705c2267a74dc9a56 -2008-02-14T03:13:16.377716Z -88 -which.linden -has-props - -tls.py -file - - - - -2008-02-20T19:57:15.000000Z -dc5cb5394ea3a29319f7302e51a7807c -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -pollhub.py -file - - - - -2008-02-20T19:57:15.000000Z -a6ac6144487b6d5f5df84262f5079955 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -api.py -file - - - - -2008-02-20T19:57:15.000000Z -dcff6139f8203bc7a1827207e06eb423 -2007-10-27T07:49:23.267939Z -37 -donovan.linden -has-props - -wsgi.py -file - - - - -2008-02-20T19:57:15.000000Z -7ce7f2d3c85243ec3ecaf1049aedbae4 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -pylibsupport.py -file - - - - -2008-02-20T19:57:15.000000Z -cf6f3b08989af055c8746292c5c8fc91 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -wrappedfd.py -file - - - - -2008-02-20T19:57:15.000000Z -5a1e9d228852226773e6c4ea1c17de6f -2008-02-13T20:04:45.776541Z -87 -nat.linden -has-props - -util.py -file - - - - -2008-02-20T19:57:15.000000Z -2dc700683fa2156f0b5c04cc0549da11 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -selecthub.py -file - - - - -2008-02-20T19:57:15.000000Z -86e451fd018d86d8b015f34d4f20fd3b -2007-10-08T07:12:35.632195Z -16 -which.linden -has-props - -timer_test.py -file - - - - -2008-02-20T19:57:15.000000Z -57ad2ed0e3cdc5b0825c05d7419ac133 -2007-12-13T19:39:23.000239Z -68 -donovan.linden -has-props - -timer.py -file - - - - -2008-02-20T19:57:15.000000Z -ebe5204bb1c220e903962b6abe0b24b4 -2008-02-19T06:15:19.940493Z -92 -which.linden -has-props - -twistedsupport.py -file - - - - -2008-02-20T19:57:15.000000Z -19b766b248cd310896dde84bedba6d3e -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -httpc_test.py -file - - - - -2008-02-20T19:57:15.000000Z -5ee0387bc46dd1f8cdff0d7059aa9bf6 -2007-12-14T00:34:51.703611Z -70 -sardonyx.linden - -httpc.py -file - - - - -2008-03-03T02:05:45.000000Z -76f48ad7feb782f4c1f0807acfecd688 -2008-02-29T22:22:47.916198Z -95 -donovan.linden -has-props - -httpd_test.py -file - - - - -2008-02-20T20:28:52.000000Z -147ad0bb4398ebf9427a1fc2b7843763 -2008-03-03T02:08:25.755808Z -97 -which.linden -has-props - -coros_test.py -file -101 - - - -2008-03-08T09:13:27.000000Z -7a922fe4bea9a193c5dee62ce86aa64c -2008-03-11T02:26:32.072967Z -101 -which.linden -has-props - -tpool.py -file - - - - -2008-02-20T19:57:15.000000Z -954ac5ec927128a5ccfe20c486c73db4 -2008-02-19T23:24:32.369211Z -93 -seeping.blister - -processes_test.py -file - - - - -2008-02-20T19:57:15.000000Z -42cd89f0b207638ed21c18db0d53b6f6 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -processes.py -file - - - - -2008-02-20T19:57:15.000000Z -4871f77ae4a77479cb4c16eff8b00897 -2007-10-08T07:12:35.632195Z -16 -which.linden -has-props - -api_test.py -file - - - - -2008-02-20T19:57:15.000000Z -fc0dd790c0de74912408bc5cc1c6087f -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -channel.py -file - - - - -2008-02-20T19:57:15.000000Z -6ef49c57d8fe793f488775fb7c7d2013 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -jsonhttp.py -file - - - - -2008-02-20T19:57:15.000000Z -a2f7e287f8df9cc66a34a5f701aa3edb -2008-01-10T00:10:39.631442Z -75 -which.linden -has-props - -db_pool_test.py -file - - - - -2008-02-20T19:57:15.000000Z -f9dcfdeb653bde2fc4bde41ee5e2d1d0 -2008-02-05T01:34:59.036551Z -85 -which.linden - -httpdate.py -file - - - - -2008-02-20T19:57:15.000000Z -9fb5c627d69fcdf9d952d38f8510f252 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -db_pool.py -file - - - - -2008-02-20T19:57:15.000000Z -e0fa71cdef20bba5cd3902a3093ca7da -2008-02-19T23:24:32.369211Z -93 -seeping.blister - -logutil.py -file - - - - -2008-02-20T19:57:15.000000Z -06f2ae2b2973cb742a8ae707fd504214 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -httpd.py -file - - - - -2008-03-03T02:05:45.000000Z -c072047f7b212b0407940805031dda86 -2008-03-03T02:08:25.755808Z -97 -which.linden -has-props - -backdoor.py -file - - - - -2008-02-20T19:57:15.000000Z -e06e68e073115125d5d209b75302e224 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -coros.py -file -101 - - - -2008-03-10T22:11:13.000000Z -0c7c37dbe89ebcb51958528b006903aa -2008-03-11T02:26:32.072967Z -101 -which.linden -has-props - -greenlib.py -file - - - - -2008-03-03T02:05:45.000000Z -996debf62c9f5dacc2dee99ed2568a25 -2008-03-02T23:59:20.899444Z -96 -which.linden -has-props - diff --git a/eventlet/.svn/format b/eventlet/.svn/format deleted file mode 100644 index 45a4fb7..0000000 --- a/eventlet/.svn/format +++ /dev/null @@ -1 +0,0 @@ -8 diff --git a/eventlet/.svn/prop-base/__init__.py.svn-base b/eventlet/.svn/prop-base/__init__.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/__init__.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/api.py.svn-base b/eventlet/.svn/prop-base/api.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/api.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/api_test.py.svn-base b/eventlet/.svn/prop-base/api_test.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/api_test.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/backdoor.py.svn-base b/eventlet/.svn/prop-base/backdoor.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/backdoor.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/channel.py.svn-base b/eventlet/.svn/prop-base/channel.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/channel.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/coros.py.svn-base b/eventlet/.svn/prop-base/coros.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/coros.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/coros_test.py.svn-base b/eventlet/.svn/prop-base/coros_test.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/coros_test.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/greenlib.py.svn-base b/eventlet/.svn/prop-base/greenlib.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/greenlib.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/httpc.py.svn-base b/eventlet/.svn/prop-base/httpc.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/httpc.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/httpd.py.svn-base b/eventlet/.svn/prop-base/httpd.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/httpd.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/httpd_test.py.svn-base b/eventlet/.svn/prop-base/httpd_test.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/httpd_test.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/httpdate.py.svn-base b/eventlet/.svn/prop-base/httpdate.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/httpdate.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/jsonhttp.py.svn-base b/eventlet/.svn/prop-base/jsonhttp.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/jsonhttp.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/kqueuehub.py.svn-base b/eventlet/.svn/prop-base/kqueuehub.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/kqueuehub.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/logutil.py.svn-base b/eventlet/.svn/prop-base/logutil.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/logutil.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/pollhub.py.svn-base b/eventlet/.svn/prop-base/pollhub.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/pollhub.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/pools.py.svn-base b/eventlet/.svn/prop-base/pools.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/pools.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/pools_test.py.svn-base b/eventlet/.svn/prop-base/pools_test.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/pools_test.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/processes.py.svn-base b/eventlet/.svn/prop-base/processes.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/processes.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/processes_test.py.svn-base b/eventlet/.svn/prop-base/processes_test.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/processes_test.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/pylibsupport.py.svn-base b/eventlet/.svn/prop-base/pylibsupport.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/pylibsupport.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/runloop.py.svn-base b/eventlet/.svn/prop-base/runloop.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/runloop.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/runloop_test.py.svn-base b/eventlet/.svn/prop-base/runloop_test.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/runloop_test.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/selecthub.py.svn-base b/eventlet/.svn/prop-base/selecthub.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/selecthub.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/stacklesssupport.py.svn-base b/eventlet/.svn/prop-base/stacklesssupport.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/stacklesssupport.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/tests.py.svn-base b/eventlet/.svn/prop-base/tests.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/tests.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/timer.py.svn-base b/eventlet/.svn/prop-base/timer.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/timer.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/timer_test.py.svn-base b/eventlet/.svn/prop-base/timer_test.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/timer_test.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/tls.py.svn-base b/eventlet/.svn/prop-base/tls.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/tls.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/twistedsupport.py.svn-base b/eventlet/.svn/prop-base/twistedsupport.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/twistedsupport.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/util.py.svn-base b/eventlet/.svn/prop-base/util.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/util.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/wrappedfd.py.svn-base b/eventlet/.svn/prop-base/wrappedfd.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/wrappedfd.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/prop-base/wsgi.py.svn-base b/eventlet/.svn/prop-base/wsgi.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/eventlet/.svn/prop-base/wsgi.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/eventlet/.svn/text-base/__init__.py.svn-base b/eventlet/.svn/text-base/__init__.py.svn-base deleted file mode 100644 index 5021bea..0000000 --- a/eventlet/.svn/text-base/__init__.py.svn-base +++ /dev/null @@ -1,24 +0,0 @@ -"""\ -@file __init__.py -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 text exists only for the purpose of not making a complete -# mockery of the above copyright header. diff --git a/eventlet/.svn/text-base/api.py.svn-base b/eventlet/.svn/text-base/api.py.svn-base deleted file mode 100644 index e9877fa..0000000 --- a/eventlet/.svn/text-base/api.py.svn-base +++ /dev/null @@ -1,309 +0,0 @@ -"""\ -@file api.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. -""" - -import sys -import socket -import string -import linecache -import inspect -import traceback - -try: - import greenlet -except ImportError: - try: - import pylibsupport - pylibsupport.emulate() - greenlet = sys.modules['greenlet'] - except ImportError: - try: - import stacklesssupport - stacklesssupport.emulate() - greenlet = sys.modules['greenlet'] - except ImportError: - raise ImportError("Unable to find an implementation of greenlet.") - -from eventlet import greenlib, tls - -__all__ = [ - 'use_hub', 'get_hub', 'sleep', 'spawn', 'kill', - 'call_after', 'exc_after', 'trampoline', 'tcp_listener', 'tcp_server', -] - - -class TimeoutError(Exception): - pass - -_threadlocal = tls.local() - -def tcp_listener(address): - """ - Listen on the given (ip, port) address with a TCP socket. - Returns a socket object which one should call accept() on to - accept a connection on the newly bound socket. - - Generally, the returned socket will be passed to tcp_server, - which accepts connections forever and spawns greenlets for - each incoming connection. - """ - from eventlet import wrappedfd, util - socket = wrappedfd.wrapped_fd(util.tcp_socket()) - util.socket_bind_and_listen(socket, address) - return socket - -def ssl_listener(address, certificate, private_key): - """Listen on the given (ip, port) address with a TCP socket that - can do SSL. - - Returns a socket object which one should call accept() on to - accept a connection on the newly bound socket. - - Generally, the returned socket will be passed to tcp_server, - which accepts connections forever and spawns greenlets for - each incoming connection. - """ - from eventlet import util - socket = util.wrap_ssl(util.tcp_socket(), certificate, private_key) - util.socket_bind_and_listen(socket, address) - socket.is_secure = True - return socket - -def connect_tcp(address): - """ - Create a TCP connection to address (host, port) and return the socket. - """ - from eventlet import wrappedfd, util - desc = wrappedfd.wrapped_fd(util.tcp_socket()) - desc.connect(address) - return desc - -def tcp_server(listensocket, server, *args, **kw): - """ - Given a socket, accept connections forever, spawning greenlets - and executing "server" for each new incoming connection. - When listensocket is closed, the tcp_server greenlet will end. - - listensocket: - The socket to accept connections from. - - server: - The callable to call when a new connection is made. - - *args: - The arguments to pass to the call to server. - - **kw: - The keyword arguments to pass to the call to server. - """ - try: - try: - while True: - spawn(server, listensocket.accept(), *args, **kw) - except socket.error, e: - # Broken pipe means it was shutdown - if e[0] != 32: - raise - finally: - listensocket.close() - -def trampoline(fd, read=None, write=None, timeout=None): - t = None - hub = get_hub() - self = greenlet.getcurrent() - fileno = getattr(fd, 'fileno', lambda: fd)() - def _do_close(fn): - hub.remove_descriptor(fn) - greenlib.switch(self, exc=socket.error(32, 'Broken pipe')) - def _do_timeout(fn): - hub.remove_descriptor(fn) - greenlib.switch(self, exc=TimeoutError()) - def cb(_fileno): - if t is not None: - t.cancel() - hub.remove_descriptor(fileno) - greenlib.switch(self, fd) - if timeout is not None: - t = hub.schedule_call(timeout, _do_timeout) - hub.add_descriptor(fileno, read and cb, write and cb, _do_close) - return hub.switch() - -def _spawn_startup(cb, args, kw, cancel=None): - try: - greenlib.switch(greenlet.getcurrent().parent) - cancel = None - finally: - if cancel is not None: - cancel() - return cb(*args, **kw) - -def _spawn(g): - g.parent = greenlet.getcurrent() - greenlib.switch(g) - - -def spawn(cb, *args, **kw): - # killable - t = None - g = greenlib.tracked_greenlet() - t = get_hub().schedule_call(0, _spawn, g) - greenlib.switch(g, (_spawn_startup, cb, args, kw, t.cancel)) - return g - -kill = greenlib.kill - -def call_after(seconds, cb, *args, **kw): - # cancellable - def startup(): - g = greenlib.tracked_greenlet() - greenlib.switch(g, (_spawn_startup, cb, args, kw)) - greenlib.switch(g) - return get_hub().schedule_call(seconds, startup) - - -def exc_after(seconds, exc): - return call_after(seconds, switch, getcurrent(), None, exc) - - -def get_default_hub(): - try: - import eventlet.kqueuehub - except ImportError: - pass - else: - return eventlet.kqueuehub - import select - if hasattr(select, 'poll'): - import eventlet.pollhub - return eventlet.pollhub - else: - import eventlet.selecthub - return eventlet.selecthub - -def use_hub(mod=None): - if mod is None: - mod = get_default_hub() - if hasattr(_threadlocal, 'hub'): - del _threadlocal.hub - if hasattr(mod, 'Hub'): - _threadlocal.Hub = mod.Hub - else: - _threadlocal.Hub = mod - -def get_hub(): - try: - hub = _threadlocal.hub - except AttributeError: - try: - _threadlocal.Hub - except AttributeError: - use_hub() - hub = _threadlocal.hub = _threadlocal.Hub() - return hub - - -def sleep(timeout=0): - hub = get_hub() - hub.schedule_call(timeout, greenlib.switch, greenlet.getcurrent()) - hub.switch() - - -switch = greenlib.switch -getcurrent = greenlet.getcurrent -GreenletExit = greenlet.GreenletExit - - -class Spew(object): - def __init__(self, trace_names=None): - self.trace_names = trace_names - - def __call__(self, frame, event, arg): - if event == 'line': - lineno = frame.f_lineno - if '__file__' in frame.f_globals: - filename = frame.f_globals['__file__'] - if (filename.endswith('.pyc') or - filename.endswith('.pyo')): - filename = filename[:-1] - name = frame.f_globals['__name__'] - line = linecache.getline(filename, lineno) - else: - name = '[unknown]' - try: - src = inspect.getsourcelines(frame) - line = src[lineno] - except IOError: - line = 'Unknown code named [%s]. VM instruction #%d' % ( - frame.f_code.co_name, frame.f_lasti) - if self.trace_names is None or name in self.trace_names: - print '%s:%s: %s' % (name, lineno, line.rstrip()) - details = '\t' - tokens = line.translate( - string.maketrans(' ,.()', '\0' * 5)).split('\0') - for tok in tokens: - if tok in frame.f_globals: - details += '%s=%r ' % (tok, frame.f_globals[tok]) - if tok in frame.f_locals: - details += '%s=%r ' % (tok, frame.f_locals[tok]) - if details.strip(): - print details - return self - - -def spew(trace_names=None): - sys.settrace(Spew(trace_names)) - - -def unspew(): - sys.settrace(None) - - -def named(name): - """Return an object given its name. The name uses a module-like -syntax, eg: - os.path.join - or - mulib.mu.Resource - """ - toimport = name - obj = None - while toimport: - try: - obj = __import__(toimport) - break - except ImportError, err: - # print 'Import error on %s: %s' % (toimport, err) # debugging spam - toimport = '.'.join(toimport.split('.')[:-1]) - if obj is None: - raise ImportError('%s could not be imported' % (name, )) - for seg in name.split('.')[1:]: - try: - obj = getattr(obj, seg) - except AttributeError: - dirobj = dir(obj) - dirobj.sort() - raise AttributeError('attribute %r missing from %r (%r) %r' % ( - seg, obj, dirobj, name)) - return obj - diff --git a/eventlet/.svn/text-base/api_test.py.svn-base b/eventlet/.svn/text-base/api_test.py.svn-base deleted file mode 100644 index b2c371a..0000000 --- a/eventlet/.svn/text-base/api_test.py.svn-base +++ /dev/null @@ -1,164 +0,0 @@ -"""\ -@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 -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 import tests -from eventlet import api, wrappedfd, util -import socket - - -def check_hub(): - # Clear through the descriptor queue - api.sleep(0) - api.sleep(0) - assert not api.get_hub().descriptors, repr(api.get_hub().descriptors) - # Stop the runloop - api.get_hub().runloop.abort() - api.sleep(0) - assert not api.get_hub().runloop.running - - -class TestApi(tests.TestCase): - mode = 'static' - def test_tcp_listener(self): - socket = api.tcp_listener(('0.0.0.0', 0)) - assert socket.getsockname()[0] == '0.0.0.0' - socket.close() - - check_hub() - - def dont_test_connect_tcp(self): - """This test is broken. Please name it test_connect_tcp and fix - the bug (or the test) so it passes. - """ - def accept_once(listenfd): - try: - conn, addr = listenfd.accept() - conn.write('hello\n') - conn.close() - finally: - listenfd.close() - - server = api.tcp_listener(('0.0.0.0', 0)) - api.spawn(accept_once, server) - - client = api.connect_tcp(('127.0.0.1', server.getsockname()[1])) - assert client.readline() == 'hello\n' - - assert client.read() == '' - client.close() - - check_hub() - - def test_server(self): - server = api.tcp_listener(('0.0.0.0', 0)) - bound_port = server.getsockname()[1] - connected = [] - - def accept_twice((conn, addr)): - print 'connected' - connected.append(True) - conn.close() - if len(connected) == 2: - server.close() - - api.call_after(0, api.connect_tcp, ('127.0.0.1', bound_port)) - api.call_after(0, api.connect_tcp, ('127.0.0.1', bound_port)) - api.tcp_server(server, accept_twice) - - assert len(connected) == 2 - - check_hub() - - def dont_test_trampoline_timeout(self): - """This test is broken. Please change it's name to test_trampoline_timeout, - and fix the bug (or fix the test) - """ - server = api.tcp_listener(('0.0.0.0', 0)) - bound_port = server.getsockname()[1] - - try: - desc = wrappedfd.wrapped_fd(util.tcp_socket()) - api.trampoline(desc, read=True, write=True, timeout=0.1) - except api.TimeoutError: - pass # test passed - else: - assert False, "Didn't timeout" - - check_hub() - - def test_timeout_cancel(self): - server = api.tcp_listener(('0.0.0.0', 0)) - bound_port = server.getsockname()[1] - - def client_connected((conn, addr)): - conn.close() - - def go(): - client = util.tcp_socket() - - desc = wrappedfd.wrapped_fd(client) - desc.connect(('127.0.0.1', bound_port)) - try: - api.trampoline(desc, read=True, write=True, timeout=0.1) - except api.TimeoutError: - assert False, "Timed out" - - server.close() - client.close() - - api.call_after(0, go) - - api.tcp_server(server, client_connected) - - check_hub() - - def dont_test_explicit_hub(self): - """This test is broken. please change it's name to test_explicit_hub - and make it pass (or fix the test) - """ - api.use_hub(Foo) - assert isinstance(api.get_hub(), Foo), api.get_hub() - - api.use_hub(api.get_default_hub()) - - check_hub() - - def test_named(self): - named_foo = api.named('api_test.Foo') - self.assertEquals( - named_foo.__name__, - "Foo") - - def test_naming_missing_class(self): - self.assertRaises( - ImportError, api.named, 'this_name_should_hopefully_not_exist.Foo') - - -class Foo(object): - pass - - -if __name__ == '__main__': - tests.main() - diff --git a/eventlet/.svn/text-base/backdoor.py.svn-base b/eventlet/.svn/text-base/backdoor.py.svn-base deleted file mode 100644 index 8f792dd..0000000 --- a/eventlet/.svn/text-base/backdoor.py.svn-base +++ /dev/null @@ -1,85 +0,0 @@ -"""\ -@file backdoor.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. -""" - -import sys -from code import InteractiveConsole -from eventlet import greenlib - -try: - sys.ps1 -except AttributeError: - sys.ps1 = '>>> ' -try: - sys.ps2 -except AttributeError: - sys.ps2 = '... ' - -class SocketConsole(greenlib.GreenletContext): - def __init__(self, desc): - # mangle the socket - self.desc = desc - readline = desc.readline - self.old = {} - self.fixups = { - 'softspace': 0, - 'isatty': lambda: True, - 'flush': lambda: None, - 'readline': lambda *a: readline(*a).replace('\r\n', '\n'), - } - for key, value in self.fixups.iteritems(): - if hasattr(desc, key): - self.old[key] = getattr(desc, key) - setattr(desc, key, value) - - def finalize(self): - # restore the state of the socket - for key in self.fixups: - try: - value = self.old[key] - except KeyError: - delattr(self.desc, key) - else: - setattr(self.desc, key, value) - self.fixups.clear() - self.old.clear() - self.desc = None - - def swap_in(self): - self.saved = sys.stdin, sys.stderr, sys.stdout - sys.stdin = sys.stdout = sys.stderr = self.desc - - def swap_out(self): - sys.stdin, sys.stderr, sys.stdout = self.saved - -def backdoor((conn, addr), locals=None): - host, port = addr - print "backdoor to %s:%s" % (host, port) - ctx = SocketConsole(conn) - ctx.register() - try: - console = InteractiveConsole(locals) - console.interact() - finally: - ctx.unregister() diff --git a/eventlet/.svn/text-base/channel.py.svn-base b/eventlet/.svn/text-base/channel.py.svn-base deleted file mode 100644 index a24799a..0000000 --- a/eventlet/.svn/text-base/channel.py.svn-base +++ /dev/null @@ -1,98 +0,0 @@ -"""\ -@file channel.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. -""" - -import collections - -from eventlet import api, greenlib - -import greenlet - -__all__ = ['channel'] - -class channel(object): - """A channel is a control flow primitive for co-routines. It is a - "thread-like" queue for controlling flow between two (or more) co-routines. - The state model is: - - * If one co-routine calls send(), it is unscheduled until another - co-routine calls receive(). - * If one co-rounte calls receive(), it is unscheduled until another - co-routine calls send(). - * Once a paired send()/receive() have been called, both co-routeines - are rescheduled. - - This is similar to: http://stackless.com/wiki/Channels - """ - balance = 0 - - def _tasklet_loop(self): - deque = self.deque = collections.deque() - hub = api.get_hub() - switch = greenlib.switch - direction, caller, args = switch() - try: - while True: - if direction == -1: - # waiting to receive - if self.balance > 0: - sender, args = deque.popleft() - hub.schedule_call(0, switch, sender) - hub.schedule_call(0, switch, caller, *args) - else: - deque.append(caller) - else: - # waiting to send - if self.balance < 0: - receiver = deque.popleft() - hub.schedule_call(0, switch, receiver, *args) - hub.schedule_call(0, switch, caller) - else: - deque.append((caller, args)) - self.balance += direction - direction, caller, args = hub.switch() - finally: - deque.clear() - del self.deque - self.balance = 0 - - def _send_tasklet(self, *args): - try: - t = self._tasklet - except AttributeError: - t = self._tasklet = greenlib.tracked_greenlet() - greenlib.switch(t, (self._tasklet_loop,)) - if args: - return greenlib.switch(t, (1, greenlet.getcurrent(), args)) - else: - return greenlib.switch(t, (-1, greenlet.getcurrent(), args)) - - def receive(self): - return self._send_tasklet() - - def send(self, value): - return self._send_tasklet(value) - - def send_exception(self, exc): - return self._send_tasklet(None, exc) diff --git a/eventlet/.svn/text-base/coros.py.svn-base b/eventlet/.svn/text-base/coros.py.svn-base deleted file mode 100644 index c53f807..0000000 --- a/eventlet/.svn/text-base/coros.py.svn-base +++ /dev/null @@ -1,457 +0,0 @@ -"""\ -@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 -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 collections -import sys -import time -import traceback - - -from eventlet import api -from eventlet import channel -from eventlet import pools -from eventlet import greenlib - - -try: - set -except NameError: # python 2.3 compatibility - from sets import Set as set - - -class Cancelled(RuntimeError): - pass - - -NOT_USED = object() - - -class event(object): - """An abstraction where an arbitrary number of coroutines - can wait for one event from another. - - Events differ from channels in two ways: - 1) calling send() does not unschedule the current coroutine - 2) send() can only be called once; use reset() to prepare the event for - another send() - They are ideal for communicating return values between coroutines. - - >>> from eventlet import coros, api - >>> evt = coros.event() - >>> def baz(b): - ... evt.send(b + 1) - ... - >>> _ = api.spawn(baz, 3) - >>> evt.wait() - 4 - """ - _result = None - def __init__(self): - self.reset() - - def reset(self): - """ Reset this event so it can be used to send again. - Can only be called after send has been called. - - >>> from eventlet import coros - >>> evt = coros.event() - >>> evt.send(1) - >>> evt.reset() - >>> evt.send(2) - >>> evt.wait() - 2 - - Calling reset multiple times in a row is an error. - - >>> evt.reset() - >>> evt.reset() - Traceback (most recent call last): - ... - AssertionError: Trying to re-reset() a fresh event. - - """ - assert self._result is not NOT_USED, 'Trying to re-reset() a fresh event.' - self.epoch = time.time() - self._result = NOT_USED - self._waiters = {} - - def wait(self): - """Wait until another coroutine calls send. - Returns the value the other coroutine passed to - send. - - >>> from eventlet import coros, api - >>> evt = coros.event() - >>> def wait_on(): - ... retval = evt.wait() - ... print "waited for", retval - >>> _ = api.spawn(wait_on) - >>> evt.send('result') - >>> api.sleep(0) - waited for result - - Returns immediately if the event has already - occured. - - >>> evt.wait() - 'result' - """ - if self._result is NOT_USED: - self._waiters[api.getcurrent()] = True - return api.get_hub().switch() - if self._exc is not None: - raise self._exc - return self._result - - def cancel(self, waiter): - """Raise an exception into a coroutine which called - wait() an this event instead of returning a value - from wait. Sends the eventlet.coros.Cancelled - exception - - waiter: The greenlet (greenlet.getcurrent()) of the - coroutine to cancel - - >>> from eventlet import coros, api - >>> evt = coros.event() - >>> def wait_on(): - ... try: - ... print "received " + evt.wait() - ... except coros.Cancelled, c: - ... print "Cancelled" - ... - >>> waiter = api.spawn(wait_on) - - The cancel call works on coroutines that are in the wait() call. - - >>> api.sleep(0) # enter the wait() - >>> evt.cancel(waiter) - >>> api.sleep(0) # receive the exception - Cancelled - - The cancel is invisible to coroutines that call wait() after cancel() - is called. This is different from send()'s behavior, where the result - is passed to any waiter regardless of the ordering of the calls. - - >>> waiter = api.spawn(wait_on) - >>> api.sleep(0) - - Cancels have no effect on the ability to send() to the event. - - >>> evt.send('stuff') - >>> api.sleep(0) - received stuff - """ - if waiter in self._waiters: - del self._waiters[waiter] - api.get_hub().schedule_call( - 0, greenlib.switch, waiter, None, Cancelled()) - - def send(self, result=None, exc=None): - """Makes arrangements for the waiters to be woken with the - result and then returns immediately to the parent. - - >>> from eventlet import coros, api - >>> evt = coros.event() - >>> def waiter(): - ... print 'about to wait' - ... result = evt.wait() - ... print 'waited for', result - >>> _ = api.spawn(waiter) - >>> api.sleep(0) - about to wait - >>> evt.send('a') - >>> api.sleep(0) - waited for a - - It is an error to call send() multiple times on the same event. - - >>> evt.send('whoops') - Traceback (most recent call last): - ... - AssertionError: Trying to re-send() an already-triggered event. - - Use reset() between send()s to reuse an event object. - """ - assert self._result is NOT_USED, 'Trying to re-send() an already-triggered event.' - self._result = result - self._exc = exc - hub = api.get_hub() - for waiter in self._waiters: - hub.schedule_call(0, greenlib.switch, waiter, self._result) - - -def execute(func, *args, **kw): - """ Executes an operation asynchronously in a new coroutine, returning - an event to retrieve the return value. - - This has the same api as the CoroutinePool.execute method; the only - difference is that this one creates a new coroutine instead of drawing - from a pool. - - >>> from eventlet import coros - >>> evt = coros.execute(lambda a: ('foo', a), 1) - >>> evt.wait() - ('foo', 1) - """ - evt = event() - def _really_execute(): - evt.send(func(*args, **kw)) - api.spawn(_really_execute) - return evt - - -class CoroutinePool(pools.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): - self._greenlets = set() - super(CoroutinePool, self).__init__(min_size, max_size) - - def _main_loop(self, sender): - """ Private, infinite loop run by a pooled coroutine. """ - while True: - recvd = sender.wait() - sender.reset() - (evt, func, args, kw) = recvd - self._safe_apply(evt, func, args, kw) - api.get_hub().runloop.cancel_timers(api.getcurrent()) - self.put(sender) - - 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) - 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) - - 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 = event() - self._greenlets.add(api.spawn(self._main_loop, sender)) - return sender - - 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 = 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) - - -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 Actor(object): - """ A free-running coroutine that accepts and processes messages. - - Kind of the equivalent of an Erlang process, really. It processes - a queue of messages in the order that they were sent. You must - subclass this and implement your own version of receive(). - - The actor's reference count will never drop to zero while the - coroutine exists; if you lose all references to the actor object - it will never be freed. - """ - def __init__(self, concurrency = 1): - """ Constructs an Actor, kicking off a new coroutine to process the messages. - - The concurrency argument specifies how many messages the actor will try - to process concurrently. If it is 1, the actor will process messages - serially. - """ - self._mailbox = collections.deque() - self._event = event() - self._killer = api.spawn(self.run_forever) - self._pool = CoroutinePool(min_size=0, max_size=concurrency) - - def run_forever(self): - """ Loops forever, continually checking the mailbox. """ - while True: - if not self._mailbox: - self._event.wait() - self._event = event() - else: - # leave the message in the mailbox until after it's - # been processed so the event doesn't get triggered - # while in the received method - self._pool.execute_async( - self.received, self._mailbox[0]) - self._mailbox.popleft() - - def cast(self, message): - """ Send a message to the actor. - - If the actor is busy, the message will be enqueued for later - consumption. There is no return value. - - >>> a = Actor() - >>> a.received = lambda msg: msg - >>> a.cast("hello") - """ - self._mailbox.append(message) - # if this is the only message, the coro could be waiting - if len(self._mailbox) == 1: - self._event.send() - - def received(self, message): - """ Called to process each incoming message. - - The default implementation just raises an exception, so - replace it with something useful! - - >>> class Greeter(Actor): - ... def received(self, (message, evt) ): - ... print "received", message - ... if evt: evt.send() - ... - >>> a = Greeter() - - This example uses events to synchronize between the actor and the main - coroutine in a predictable manner, but this kinda defeats the point of - the Actor, so don't do it in a real application. - - >>> evt = event() - >>> a.cast( ("message 1", evt) ) - >>> evt.wait() # force it to run at this exact moment - received message 1 - >>> evt.reset() - >>> a.cast( ("message 2", None) ) - >>> a.cast( ("message 3", evt) ) - >>> evt.wait() - received message 2 - received message 3 - - >>> api.kill(a._killer) # test cleanup - """ - raise NotImplementedError() - - -def _test(): - print "Running doctests. There will be no further output if they succeed." - import doctest - doctest.testmod() - -if __name__ == "__main__": - _test() diff --git a/eventlet/.svn/text-base/coros_test.py.svn-base b/eventlet/.svn/text-base/coros_test.py.svn-base deleted file mode 100644 index a72bc7a..0000000 --- a/eventlet/.svn/text-base/coros_test.py.svn-base +++ /dev/null @@ -1,300 +0,0 @@ -"""\ -@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. -""" -from eventlet import tests -from eventlet import timer -from eventlet import coros, api - -class TestEvent(tests.TestCase): - mode = 'static' - def setUp(self): - # raise an exception if we're waiting forever - self._cancel_timeout = api.exc_after(1, RuntimeError()) - - def tearDown(self): - self._cancel_timeout.cancel() - - def test_waiting_for_event(self): - evt = coros.event() - value = 'some stuff' - def send_to_event(): - evt.send(value) - api.spawn(send_to_event) - self.assertEqual(evt.wait(), value) - - def test_multiple_waiters(self): - evt = coros.event() - value = 'some stuff' - results = [] - def wait_on_event(i_am_done): - evt.wait() - results.append(True) - i_am_done.send() - - waiters = [] - count = 5 - for i in range(count): - waiters.append(coros.event()) - api.spawn(wait_on_event, waiters[-1]) - evt.send() - - for w in waiters: - w.wait() - - self.assertEqual(len(results), count) - - def test_cancel(self): - evt = coros.event() - # close over the current coro so we can cancel it explicitly - current = api.getcurrent() - def cancel_event(): - evt.cancel(current) - api.spawn(cancel_event) - - self.assertRaises(coros.Cancelled, evt.wait) - - def test_reset(self): - evt = coros.event() - - # calling reset before send should throw - self.assertRaises(AssertionError, evt.reset) - - value = 'some stuff' - def send_to_event(): - evt.send(value) - api.spawn(send_to_event) - self.assertEqual(evt.wait(), value) - - # now try it again, and we should get the same exact value, - # and we shouldn't be allowed to resend without resetting - value2 = 'second stuff' - self.assertRaises(AssertionError, evt.send, value2) - self.assertEqual(evt.wait(), value) - - # reset and everything should be happy - evt.reset() - def send_to_event2(): - evt.send(value2) - api.spawn(send_to_event2) - self.assertEqual(evt.wait(), value2) - - def test_double_exception(self): - evt = coros.event() - # send an exception through the event - evt.send(exc=RuntimeError()) - self.assertRaises(RuntimeError, evt.wait) - evt.reset() - # shouldn't see the RuntimeError again - api.exc_after(0.001, api.TimeoutError) - 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) - - def test_timer_cancel(self): - def some_work(): - t = timer.Timer(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() - - -class IncrActor(coros.Actor): - def received(self, evt): - self.value = getattr(self, 'value', 0) + 1 - if evt: evt.send() - -class TestActor(tests.TestCase): - mode = 'static' - def setUp(self): - # raise an exception if we're waiting forever - self._cancel_timeout = api.exc_after(1, api.TimeoutError()) - self.actor = IncrActor() - - def tearDown(self): - self._cancel_timeout.cancel() - api.kill(self.actor._killer) - - def test_cast(self): - evt = coros.event() - self.actor.cast(evt) - evt.wait() - evt.reset() - self.assertEqual(self.actor.value, 1) - self.actor.cast(evt) - evt.wait() - self.assertEqual(self.actor.value, 2) - - def test_cast_multi_1(self): - # make sure that both messages make it in there - evt = coros.event() - evt1 = coros.event() - self.actor.cast(evt) - self.actor.cast(evt1) - evt.wait() - evt1.wait() - self.assertEqual(self.actor.value, 2) - - def test_cast_multi_2(self): - # the actor goes through a slightly different code path if it - # is forced to enter its event loop prior to any cast()s - api.sleep(0) - self.test_cast_multi_1() - - def test_sleeping_during_received(self): - # ensure that even if the received method cooperatively - # yields, eventually all messages are delivered - msgs = [] - waiters = [] - def received( (message, evt) ): - api.sleep(0) - msgs.append(message) - evt.send() - self.actor.received = received - - waiters.append(coros.event()) - self.actor.cast( (1, waiters[-1])) - api.sleep(0) - waiters.append(coros.event()) - self.actor.cast( (2, waiters[-1]) ) - waiters.append(coros.event()) - self.actor.cast( (3, waiters[-1]) ) - api.sleep(0) - waiters.append(coros.event()) - self.actor.cast( (4, waiters[-1]) ) - waiters.append(coros.event()) - self.actor.cast( (5, waiters[-1]) ) - for evt in waiters: - evt.wait() - self.assertEqual(msgs, [1,2,3,4,5]) - - - def test_raising_received(self): - msgs = [] - def received( (message, evt) ): - evt.send() - if message == 'fail': - raise RuntimeError() - else: - msgs.append(message) - - self.actor.received = received - - evt = coros.event() - self.actor.cast( ('fail', evt) ) - evt.wait() - evt.reset() - self.actor.cast( ('should_appear', evt) ) - evt.wait() - self.assertEqual(['should_appear'], msgs) - - def test_multiple(self): - self.actor = IncrActor(concurrency=2) - total = [0] - def received( (func, ev, value) ): - func() - total[0] += value - ev.send() - self.actor.received = received - - def onemoment(): - api.sleep(0.1) - - evt = coros.event() - evt1 = coros.event() - - self.actor.cast( (onemoment, evt, 1) ) - self.actor.cast( (lambda: None, evt1, 2) ) - - evt1.wait() - self.assertEqual(total[0], 2) - # both coroutines should have been used - self.assertEqual(self.actor._pool.current_size, 2) - self.assertEqual(self.actor._pool.free(), 1) - evt.wait() - self.assertEqual(total[0], 3) - self.assertEqual(self.actor._pool.free(), 2) - -if __name__ == '__main__': - tests.main() diff --git a/eventlet/.svn/text-base/db_pool.py.svn-base b/eventlet/.svn/text-base/db_pool.py.svn-base deleted file mode 100644 index 3c91793..0000000 --- a/eventlet/.svn/text-base/db_pool.py.svn-base +++ /dev/null @@ -1,220 +0,0 @@ -"""\ -@file db_pool.py -@brief Uses saranwrap to implement a pool of nonblocking database connections to a db server. - -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 os, sys - -from eventlet.pools import Pool -from eventlet.processes import DeadProcess -from eventlet import saranwrap - -class DatabaseConnector(object): - """\ -@brief This is an object which will maintain a collection of database -connection pools keyed on host,databasename""" - def __init__(self, module, credentials, min_size = 0, max_size = 4, conn_pool=None, *args, **kwargs): - """\ - @brief constructor - @param min_size the minimum size of a child pool. - @param max_size the maximum size of a child pool.""" - assert(module) - self._conn_pool_class = conn_pool - if self._conn_pool_class is None: - self._conn_pool_class = ConnectionPool - self._module = module - self._min_size = min_size - self._max_size = max_size - self._args = args - self._kwargs = kwargs - self._credentials = credentials # this is a map of hostname to username/password - self._databases = {} - - def credentials_for(self, host): - if host in self._credentials: - return self._credentials[host] - else: - return self._credentials.get('default', None) - - def get(self, host, dbname): - key = (host, dbname) - if key not in self._databases: - new_kwargs = self._kwargs.copy() - new_kwargs['db'] = dbname - new_kwargs['host'] = host - new_kwargs.update(self.credentials_for(host)) - dbpool = self._conn_pool_class(self._module, min_size=self._min_size, max_size=self._max_size, - *self._args, **new_kwargs) - self._databases[key] = dbpool - - return self._databases[key] - -class BaseConnectionPool(Pool): - # *TODO: we need to expire and close connections if they've been - # idle for a while, so that system-wide connection count doesn't - # monotonically increase forever - def __init__(self, db_module, min_size = 0, max_size = 4, *args, **kwargs): - assert(db_module) - self._db_module = db_module - self._args = args - self._kwargs = kwargs - super(BaseConnectionPool, self).__init__(min_size, max_size) - - def get(self): - # wrap the connection for easier use - conn = super(BaseConnectionPool, self).get() - return PooledConnectionWrapper(conn, self) - - def put(self, conn): - # rollback any uncommitted changes, so that the next client - # has a clean slate. This also pokes the connection to see if - # it's dead or None - try: - conn.rollback() - except AttributeError, e: - # this means it's already been destroyed, so we don't need to print anything - conn = None - except: - # we don't care what the exception was, we just know the - # connection is dead - print "WARNING: connection.rollback raised: %s" % (sys.exc_info()[1]) - conn = None - - # unwrap the connection for storage - if isinstance(conn, GenericConnectionWrapper): - if conn: - base = conn._base - conn._destroy() - conn = base - else: - conn = None - - if conn is not None: - super(BaseConnectionPool, self).put(conn) - else: - self.current_size -= 1 - - -class SaranwrappedConnectionPool(BaseConnectionPool): - """A pool which gives out saranwrapped database connections from a pool - """ - def create(self): - return saranwrap.wrap(self._db_module).connect(*self._args, **self._kwargs) - -class TpooledConnectionPool(BaseConnectionPool): - """A pool which gives out tpool.Proxy-based database connections from a pool. - """ - def create(self): - from eventlet import tpool - try: - # *FIX: this is a huge hack that will probably only work for MySQLdb - autowrap = (self._db_module.cursors.DictCursor,) - except: - autowrap = () - return tpool.Proxy(self._db_module.connect(*self._args, **self._kwargs), - autowrap=autowrap) - -class RawConnectionPool(BaseConnectionPool): - """A pool which gives out plain database connections from a pool. - """ - def create(self): - return self._db_module.connect(*self._args, **self._kwargs) - -# default connection pool is the tpool one -ConnectionPool = TpooledConnectionPool - - -class GenericConnectionWrapper(object): - def __init__(self, baseconn): - self._base = baseconn - def __enter__(self): return self._base.__enter__() - def __exit__(self, exc, value, tb): return self._base.__exit__(exc, value, tb) - def __repr__(self): return self._base.__repr__() - def affected_rows(self): return self._base.affected_rows() - def autocommit(self,*args, **kwargs): return self._base.autocommit(*args, **kwargs) - def begin(self): return self._base.begin() - def change_user(self,*args, **kwargs): return self._base.change_user(*args, **kwargs) - def character_set_name(self,*args, **kwargs): return self._base.character_set_name(*args, **kwargs) - def close(self,*args, **kwargs): return self._base.close(*args, **kwargs) - def commit(self,*args, **kwargs): return self._base.commit(*args, **kwargs) - def cursor(self, cursorclass=None, **kwargs): return self._base.cursor(cursorclass, **kwargs) - def dump_debug_info(self,*args, **kwargs): return self._base.dump_debug_info(*args, **kwargs) - def errno(self,*args, **kwargs): return self._base.errno(*args, **kwargs) - def error(self,*args, **kwargs): return self._base.error(*args, **kwargs) - def errorhandler(self, conn, curs, errcls, errval): return self._base.errorhandler(conn, curs, errcls, errval) - def literal(self, o): return self._base.literal(o) - 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 show_warnings(self): return self._base.show_warnings() - 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 query(self,*args, **kwargs): return self._base.query(*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 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 show_warnings(self): return self._base.show_warnings() - def shutdown(self,*args, **kwargs): return self._base.shutdown(*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 store_result(self,*args, **kwargs): return self._base.store_result(*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 use_result(self,*args, **kwargs): return self._base.use_result(*args, **kwargs) - def warning_count(self): return self._base.warning_count() - - -class PooledConnectionWrapper(GenericConnectionWrapper): - """ A connection wrapper where: - - the close method returns the connection to the pool instead of closing it directly - - you can do if conn: - - returns itself to the pool if it gets garbage collected - """ - def __init__(self, baseconn, pool): - super(PooledConnectionWrapper, self).__init__(baseconn) - self._pool = pool - - def __nonzero__(self): - return (hasattr(self, '_base') and bool(self._base)) - - def _destroy(self): - self._pool = None - try: - del self._base - except AttributeError: - pass - - def close(self): - """ Return the connection to the pool, and remove the - reference to it so that you can't use it again through this - wrapper object. - """ - if self and self._pool: - self._pool.put(self) - self._destroy() - - def __del__(self): - self.close() diff --git a/eventlet/.svn/text-base/db_pool_test.py.svn-base b/eventlet/.svn/text-base/db_pool_test.py.svn-base deleted file mode 100644 index df1a043..0000000 --- a/eventlet/.svn/text-base/db_pool_test.py.svn-base +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/python -# @file test_mysql_pool.py -# @brief Test cases for mysql_pool -# -# 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 os.path - -from eventlet import api, coros, tests -from eventlet import db_pool - -class DBTester(object): - def setUp(self): - self.create_db() - self.connection = None - connection = self._dbmodule.connect(**self._auth) - cursor = connection.cursor() - cursor.execute("""CREATE TABLE gargleblatz - ( - a INTEGER - ) ENGINE = InnoDB;""") - connection.commit() - cursor.close() - - def tearDown(self): - if self.connection is not None: - self.connection.close() - self.drop_db() - - def set_up_test_table(self, connection = None): - if connection is None: - if self.connection is None: - self.connection = self._dbmodule.connect(**self._auth) - connection = self.connection - - cursor = connection.cursor() - cursor.execute("""CREATE TEMPORARY TABLE test_table - ( - row_id INTEGER PRIMARY KEY AUTO_INCREMENT, - value_int INTEGER, - value_float FLOAT, - value_string VARCHAR(200), - value_uuid CHAR(36), - value_binary BLOB, - value_binary_string VARCHAR(200) BINARY, - value_enum ENUM('Y','N'), - created TIMESTAMP - ) ENGINE = InnoDB;""") - connection.commit() - cursor.close() - -class TestDBConnectionPool(DBTester): - def setUp(self): - super(TestDBConnectionPool, self).setUp() - self.pool = self.create_pool() - self.connection = self.pool.get() - - def tearDown(self): - self.pool.put(self.connection) - super(TestDBConnectionPool, self).tearDown() - - def assert_cursor_works(self, cursor): - cursor.execute("show full processlist") - rows = cursor.fetchall() - self.assert_(rows) - - def test_connecting(self): - self.assert_(self.connection is not None) - - def test_create_cursor(self): - cursor = self.connection.cursor() - cursor.close() - - def test_run_query(self): - cursor = self.connection.cursor() - self.assert_cursor_works(cursor) - cursor.close() - - def test_run_bad_query(self): - cursor = self.connection.cursor() - try: - cursor.execute("garbage blah blah") - self.assert_(False) - except AssertionError: - raise - except Exception, e: - pass - cursor.close() - - def test_put_none(self): - # the pool is of size 1, and its only connection is out - self.assert_(self.pool.free() == 0) - self.pool.put(None) - # ha ha we fooled it into thinking that we had a dead process - self.assert_(self.pool.free() == 1) - conn2 = self.pool.get() - self.assert_(conn2 is not None) - self.assert_(conn2.cursor) - del conn2 - - def test_close_does_a_put(self): - self.assert_(self.pool.free() == 0) - self.connection.close() - self.assert_(self.pool.free() == 1) - self.assertRaises(AttributeError, self.connection.cursor) - - def test_deletion_does_a_put(self): - self.assert_(self.pool.free() == 0) - self.connection = None - self.assert_(self.pool.free() == 1) - - def test_put_doesnt_double_wrap(self): - self.pool.put(self.connection) - conn = self.pool.get() - self.assert_(not isinstance(conn._base, db_pool.PooledConnectionWrapper)) - - def test_bool(self): - self.assert_(self.connection) - self.connection.close() - self.assert_(not self.connection) - - def fill_test_table(self, conn): - curs = conn.cursor() - for i in range(1000): - curs.execute('insert into test_table (value_int) values (%s)' % i) - conn.commit() - - def test_returns_immediately(self): - self.pool = self.create_pool() - conn = self.pool.get() - self.set_up_test_table(conn) - self.fill_test_table(conn) - curs = conn.cursor() - results = [] - SHORT_QUERY = "select * from test_table" - evt = coros.event() - def a_query(): - self.assert_cursor_works(curs) - curs.execute(SHORT_QUERY) - results.append(2) - evt.send() - evt2 = coros.event() - api.spawn(a_query) - results.append(1) - self.assertEqual([1], results) - evt.wait() - self.assertEqual([1, 2], results) - - def test_connection_is_clean_after_put(self): - self.pool = self.create_pool() - conn = self.pool.get() - self.set_up_test_table(conn) - curs = conn.cursor() - for i in range(10): - curs.execute('insert into test_table (value_int) values (%s)' % i) - # do not commit :-) - self.pool.put(conn) - del conn - conn2 = self.pool.get() - curs2 = conn2.cursor() - for i in range(10): - curs2.execute('insert into test_table (value_int) values (%s)' % i) - conn2.commit() - rows = curs2.execute("select * from test_table") - # we should have only inserted them once - self.assertEqual(10, rows) - - def test_visibility_from_other_connections(self): - # *FIX: use some non-indra-specific table for testing (can't use a temp table) - self.pool = self.create_pool(3) - conn = self.pool.get() - conn2 = self.pool.get() - curs = conn.cursor() - try: - curs2 = conn2.cursor() - rows2 = curs2.execute("insert into gargleblatz (a) values (%s)" % (314159)) - self.assertEqual(rows2, 1) - conn2.commit() - selection_query = "select * from gargleblatz" - rows2 = curs2.execute(selection_query) - self.assertEqual(rows2, 1) - del curs2 - del conn2 - # create a new connection, it should see the addition - conn3 = self.pool.get() - curs3 = conn3.cursor() - rows3 = curs3.execute(selection_query) - self.assertEqual(rows3, 1) - # now, does the already-open connection see it? - rows = curs.execute(selection_query) - self.assertEqual(rows, 1) - finally: - # clean up my litter - curs.execute("delete from gargleblatz where a=314159") - conn.commit() - - - def test_two_simultaneous_connections(self): - self.pool = self.create_pool(2) - conn = self.pool.get() - self.set_up_test_table(conn) - self.fill_test_table(conn) - curs = conn.cursor() - conn2 = self.pool.get() - self.set_up_test_table(conn2) - self.fill_test_table(conn2) - curs2 = conn2.cursor() - results = [] - LONG_QUERY = "select * from test_table" - SHORT_QUERY = "select * from test_table where row_id <= 20" - - evt = coros.event() - def long_running_query(): - self.assert_cursor_works(curs) - curs.execute(LONG_QUERY) - results.append(1) - evt.send() - evt2 = coros.event() - def short_running_query(): - self.assert_cursor_works(curs2) - curs2.execute(SHORT_QUERY) - results.append(2) - evt2.send() - - api.spawn(long_running_query) - api.spawn(short_running_query) - evt.wait() - evt2.wait() - #print "results %s" % results - results.sort() - self.assertEqual([1, 2], results) - - -class TestTpoolConnectionPool(TestDBConnectionPool): - def create_pool(self, max_items = 1): - return db_pool.TpooledConnectionPool(self._dbmodule, 0, max_items, **self._auth) - - -class TestSaranwrapConnectionPool(TestDBConnectionPool): - def create_pool(self, max_items = 1): - return db_pool.SaranwrappedConnectionPool(self._dbmodule, 0, max_items, **self._auth) - -class TestMysqlConnectionPool(object): - def setUp(self): - import MySQLdb - self._dbmodule = MySQLdb - try: - import simplejson - import os.path - auth_utf8 = simplejson.load(open(os.path.join(os.path.dirname(__file__), 'auth.json'))) - # have to convert unicode objects to str objects because mysqldb is dum - self._auth = dict([(str(k), str(v)) - for k, v in auth_utf8.items()]) - except (IOError, ImportError), e: - self._auth = {'host': 'localhost','user': 'root','passwd': '','db': 'persist0'} - super(TestMysqlConnectionPool, self).setUp() - - def create_db(self): - auth = self._auth.copy() - try: - self.drop_db() - except Exception: - pass - dbname = auth.pop('db') - db = self._dbmodule.connect(**auth).cursor() - db.execute("create database "+dbname) - db.close() - del db - - def drop_db(self): - db = self._dbmodule.connect(**self._auth).cursor() - db.execute("drop database "+self._auth['db']) - db.close() - del db - -class TestMysqlTpool(TestMysqlConnectionPool, TestTpoolConnectionPool, tests.TestCase): - pass - -class TestMysqlSaranwrap(TestMysqlConnectionPool, TestSaranwrapConnectionPool, tests.TestCase): - pass - - -if __name__ == '__main__': - try: - import MySQLdb - except ImportError: - print "Unable to import MySQLdb, skipping db_pool_test." - else: - tests.main() -else: - import MySQLdb diff --git a/eventlet/.svn/text-base/greenlib.py.svn-base b/eventlet/.svn/text-base/greenlib.py.svn-base deleted file mode 100644 index 1dbf01e..0000000 --- a/eventlet/.svn/text-base/greenlib.py.svn-base +++ /dev/null @@ -1,331 +0,0 @@ -"""\ -@file greenlib.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. -""" -import sys -import itertools - -import greenlet - -from eventlet import tls - -__all__ = [ - 'switch', 'kill', 'tracked_greenlets', - 'greenlet_id', 'greenlet_dict', 'GreenletContext', - 'tracked_greenlet', -] - -try: - reversed -except NameError: - def reversed(something): - for x in something[::-1]: - yield x - -_threadlocal = tls.local() - -def tracked_greenlet(): - """ - Returns a greenlet that has a greenlet-local dictionary and can be - used with GreenletContext and enumerated with tracked_greenlets - """ - return greenlet.greenlet(greenlet_body) - -class GreenletContextManager(object): - """ - Per-thread manager for GreenletContext. Created lazily on registration - """ - def __new__(cls, *args, **kw): - dct = greenlet_dict() - self = dct.get('greenlet_context', None) - if self is not None: - return self - self = super(GreenletContextManager, cls).__new__(cls, *args, **kw) - dct['greenlet_context'] = self - self.contexts = [] - return self - - def add_context(self, ctx): - fn = getattr(ctx, '_swap_in', None) - if fn is not None: - fn() - self.contexts.append(ctx) - - def remove_context(self, ctx): - try: - idx = self.contexts.index(ctx) - except ValueError: - return - else: - del self.contexts[idx] - fn = getattr(ctx, '_swap_out', None) - if fn is not None: - fn() - fn = getattr(ctx, '_finalize', None) - if fn is not None: - fn() - - def swap_in(self): - for ctx in self.contexts: - fn = getattr(ctx, '_swap_in', None) - if fn is not None: - fn() - - def swap_out(self): - for ctx in reversed(self.contexts): - fn = getattr(ctx, '_swap_out', None) - if fn is not None: - fn() - - def finalize(self): - for ctx in reversed(self.contexts): - fn = getattr(ctx, '_swap_out', None) - if fn is not None: - fn() - fn = getattr(ctx, '_finalize', None) - if fn is not None: - fn() - del self.contexts[:] - try: - del greenlet_dict()['greenlet_context'] - except KeyError: - pass - -class GreenletContext(object): - """ - A context manager to be triggered when a specific tracked greenlet is - swapped in, swapped out, or finalized. - - To use, subclass and override the swap_in, swap_out, and/or finalize - methods, for example:: - - import greenlib - from greenlib import greenlet_id, tracked_greenlet, switch - - class NotifyContext(greenlib.GreenletContext): - - def swap_in(self): - print "swap_in" - - def swap_out(self): - print "swap_out" - - def finalize(self): - print "finalize" - - def another_greenlet(): - print "another_greenlet" - - def notify_demo(): - print "starting" - NotifyContext().register() - switch(tracked_greenlet(), (another_greenlet,)) - print "finishing" - # we could have kept the NotifyContext object - # to unregister it here but finalization of all - # contexts is implicit when the greenlet returns - - t = tracked_greenlet() - switch(t, (notify_demo,)) - - The output should be: - - starting - swap_in - swap_out - another_greenlet - swap_in - finishing - swap_out - finalize - - """ - _balance = 0 - - def _swap_in(self): - if self._balance != 0: - raise RuntimeError("balance != 0: %r" % (self._balance,)) - self._balance = self._balance + 1 - fn = getattr(self, 'swap_in', None) - if fn is not None: - fn() - - def _swap_out(self): - if self._balance != 1: - raise RuntimeError("balance != 1: %r" % (self._balance,)) - self._balance = self._balance - 1 - fn = getattr(self, 'swap_out', None) - if fn is not None: - fn() - - def register(self): - GreenletContextManager().add_context(self) - - def unregister(self): - GreenletContextManager().remove_context(self) - - def _finalize(self): - fn = getattr(self, 'finalize', None) - if fn is not None: - fn() - - -def kill(g): - """ - Kill the given greenlet if it is alive by sending it a GreenletExit. - - Note that of any other exception is raised, it will pass-through! - """ - if not g: - return - kill_exc = greenlet.GreenletExit() - try: - try: - g.parent = greenlet.getcurrent() - except ValueError: - pass - try: - switch(g, exc=kill_exc) - except SwitchingToDeadGreenlet: - pass - except greenlet.GreenletExit, e: - if e is not kill_exc: - raise - -def tracked_greenlets(): - """ - Return a list of greenlets tracked in this thread. Tracked greenlets - use greenlet_body() to ensure that they have greenlet-local storage. - """ - try: - return _threadlocal.greenlets.keys() - except AttributeError: - return [] - -def greenlet_id(): - """ - Get the id of the current tracked greenlet, returns None if the - greenlet is not tracked. - """ - try: - d = greenlet_dict() - except RuntimeError: - return None - return d['greenlet_id'] - -def greenlet_dict(): - """ - Return the greenlet local storage for this greenlet. Raises RuntimeError - if this greenlet is not tracked. - """ - self = greenlet.getcurrent() - try: - return _threadlocal.greenlets[self] - except (AttributeError, KeyError): - raise RuntimeError("greenlet %r is not tracked" % (self,)) - -def _greenlet_context(dct=None): - if dct is None: - try: - dct = greenlet_dict() - except RuntimeError: - return None - return dct.get('greenlet_context', None) - -def _greenlet_context_call(name, dct=None): - ctx = _greenlet_context(dct) - fn = getattr(ctx, name, None) - if fn is not None: - fn() - -def greenlet_body(value, exc): - """ - Track the current greenlet during the execution of the given callback, - normally you would use tracked_greenlet() to get a greenlet that uses this. - - Greenlets using this body must be greenlib.switch()'ed to - """ - if exc is not None: - if isinstance(exc, tuple): - raise exc[0], exc[1], exc[2] - raise exc - cb, args = value[0], value[1:] - try: - greenlets = _threadlocal.greenlets - except AttributeError: - greenlets = _threadlocal.greenlets = {} - else: - if greenlet.getcurrent() in greenlets: - raise RuntimeError("greenlet_body can not be called recursively!") - try: - greenlet_id = _threadlocal.next_greenlet_id.next() - except AttributeError: - greenlet_id = 1 - _threadlocal.next_greenlet_id = itertools.count(2) - greenlets[greenlet.getcurrent()] = {'greenlet_id': greenlet_id} - try: - return cb(*args) - finally: - _greenlet_context_call('finalize') - greenlets.pop(greenlet.getcurrent(), None) - - -class SwitchingToDeadGreenlet(RuntimeError): - pass - - -def switch(other=None, value=None, exc=None): - """ - Switch to another greenlet, passing value or exception - """ - self = greenlet.getcurrent() - if other is None: - other = self.parent - if other is None: - other = self - if not (other or hasattr(other, 'run')): - raise SwitchingToDeadGreenlet("Switching to dead greenlet %r %r %r" % (other, value, exc)) - _greenlet_context_call('swap_out') - sys.exc_clear() # don't pass along exceptions to the other coroutine - try: - rval = other.switch(value, exc) - if not rval or not other: - res, exc = rval, None - else: - res, exc = rval - except: - res, exc = None, sys.exc_info() - _greenlet_context_call('swap_in') - # *NOTE: we don't restore exc_info, so don't switch inside an - # exception handler and then call sys.exc_info() or use bare - # raise. Instead, explicitly save off the exception before - # switching. We need an extension that allows us to restore the - # exception state at this point because vanilla Python doesn't - # allow that. - if isinstance(exc, tuple): - typ, exc, tb = exc - raise typ, exc, tb - elif exc is not None: - raise exc - - return res diff --git a/eventlet/.svn/text-base/httpc.py.svn-base b/eventlet/.svn/text-base/httpc.py.svn-base deleted file mode 100644 index 63c6caf..0000000 --- a/eventlet/.svn/text-base/httpc.py.svn-base +++ /dev/null @@ -1,597 +0,0 @@ -"""\ -@file httpc.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 datetime -import httplib -import os.path -import os -import time -import urlparse - - -_old_HTTPConnection = httplib.HTTPConnection -_old_HTTPSConnection = httplib.HTTPSConnection - - -HTTP_TIME_FORMAT = '%a, %d %b %Y %H:%M:%S GMT' -to_http_time = lambda t: time.strftime(HTTP_TIME_FORMAT, time.gmtime(t)) - -try: - - from mx import DateTime - def from_http_time(t, defaultdate=None): - return int(DateTime.Parser.DateTimeFromString( - t, defaultdate=defaultdate).gmticks()) - -except ImportError: - - import calendar - parse_formats = (HTTP_TIME_FORMAT, # RFC 1123 - '%A, %d-%b-%y %H:%M:%S GMT', # RFC 850 - '%a %b %d %H:%M:%S %Y') # asctime - def from_http_time(t, defaultdate=None): - for parser in parse_formats: - try: - return calendar.timegm(time.strptime(t, parser)) - except ValueError: - continue - return defaultdate - - -def host_and_port_from_url(url): - """@brief Simple function to get host and port from an http url. - @return Returns host, port and port may be None. - """ - host = None - port = None - parsed_url = urlparse.urlparse(url) - try: - host, port = parsed_url[1].split(':') - except ValueError: - host = parsed_url[1].split(':') - return host, port - - -def better_putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): - self.method = method - self.path = url - try: - # Python 2.4 and above - self.old_putrequest(method, url, skip_host, skip_accept_encoding) - except TypeError: - # Python 2.3 and below - self.old_putrequest(method, url, skip_host) - - -class HttpClient(httplib.HTTPConnection): - """A subclass of httplib.HTTPConnection that provides a better - putrequest that records the method and path on the request object. - """ - def __init__(self, host, port=None, strict=None): - _old_HTTPConnection.__init__(self, host, port, strict) - - old_putrequest = httplib.HTTPConnection.putrequest - putrequest = better_putrequest - -class HttpsClient(httplib.HTTPSConnection): - """A subclass of httplib.HTTPSConnection that provides a better - putrequest that records the method and path on the request object. - """ - old_putrequest = httplib.HTTPSConnection.putrequest - putrequest = better_putrequest - - -def wrap_httplib_with_httpc(): - """Replace httplib's implementations of these classes with our enhanced ones. - - Needed to work around code that uses httplib directly.""" - httplib.HTTP._connection_class = httplib.HTTPConnection = HttpClient - httplib.HTTPS._connection_class = httplib.HTTPSConnection = HttpsClient - - - -class FileScheme(object): - """Retarded scheme to local file wrapper.""" - host = '' - port = '' - reason = '' - - def __init__(self, location): - pass - - def request(self, method, fullpath, body='', headers=None): - self.status = 200 - self.msg = '' - self.path = fullpath.split('?')[0] - self.method = method = method.lower() - assert method in ('get', 'put', 'delete') - if method == 'delete': - try: - os.remove(self.path) - except OSError: - pass # don't complain if already deleted - elif method == 'put': - try: - f = file(self.path, 'w') - f.write(body) - f.close() - except IOError, e: - self.status = 500 - self.raise_connection_error() - elif method == 'get': - if not os.path.exists(self.path): - self.status = 404 - self.raise_connection_error(NotFound) - - def connect(self): - pass - - def getresponse(self): - return self - - def getheader(self, header): - if header == 'content-length': - try: - return os.path.getsize(self.path) - except OSError: - return 0 - - def read(self, howmuch=None): - if self.method == 'get': - try: - fl = file(self.path, 'r') - if howmuch is None: - return fl.read() - else: - return fl.read(howmuch) - except IOError: - self.status = 500 - self.raise_connection_error() - return '' - - def raise_connection_error(self, klass=None): - if klass is None: - klass=ConnectionError - raise klass(_Params('file://' + self.path, self.method)) - - def close(self): - """We're challenged here, and read the whole file rather than - integrating with this lib. file object already out of scope at this - point""" - pass - -class _Params(object): - def __init__(self, url, method, body='', headers=None, dumper=None, - loader=None, use_proxy=False, ok=(), aux=None): - ''' - @param connection The connection (as returned by make_connection) to use for the request. - @param method HTTP method - @param url Full url to make request on. - @param body HTTP body, if necessary for the method. Can be any object, assuming an appropriate dumper is also provided. - @param headers Dict of header name to header value - @param dumper Method that formats the body as a string. - @param loader Method that converts the response body into an object. - @param use_proxy Set to True if the connection is to a proxy. - @param ok Set of valid response statuses. If the returned status is not in this list, an exception is thrown. - ''' - self.instance = None - self.url = url - self.path = url - self.method = method - self.body = body - if headers is None: - self.headers = {} - else: - self.headers = headers - self.dumper = dumper - self.loader = loader - self.use_proxy = use_proxy - self.ok = ok or (200, 201, 204) - self.orig_body = body - self.aux = aux - - -class _LocalParams(_Params): - def __init__(self, params, **kwargs): - self._delegate = params - for k, v in kwargs.iteritems(): - setattr(self, k, v) - - def __getattr__(self, key): - return getattr(self._delegate, key) - - -class ConnectionError(Exception): - """Detailed exception class for reporting on http connection problems. - - There are lots of subclasses so you can use closely-specified - exception clauses.""" - def __init__(self, params): - self.params = params - Exception.__init__(self) - - def location(self): - return self.params.response.msg.dict.get('location') - - def expired(self): - # 14.21 Expires - # - # HTTP/1.1 clients and caches MUST treat other invalid date - # formats, especially including the value "0", as in the past - # (i.e., "already expired"). - expires = from_http_time( - self.params.response_headers.get('expires', '0'), - defaultdate=DateTime.Epoch) - return time.time() > expires - - def __repr__(self): - response = self.params.response - return "%s(url=%r, method=%r, status=%r, reason=%r, body=%r)" % ( - self.__class__.__name__, self.params.url, self.params.method, - response.status, response.reason, self.params.body) - - __str__ = __repr__ - - -class UnparseableResponse(ConnectionError): - """Raised when a loader cannot parse the response from the server.""" - def __init__(self, content_type, response, url): - self.content_type = content_type - self.response = response - self.url = url - Exception.__init__(self) - - def __repr__(self): - return "Could not parse the data at the URL %r of content-type %r\nData:\n%r)" % ( - self.url, self.content_type, self.response) - - __str__ = __repr__ - - -class Accepted(ConnectionError): - """ 202 Accepted """ - pass - - -class Retriable(ConnectionError): - def retry_method(self): - return self.params.method - - def retry_url(self): - return self.location() or self.url() - - def retry_(self): - params = _LocalParams(self.params, - url=self.retry_url(), - method=self.retry_method()) - return self.params.instance.request_(params) - - def retry(self): - return self.retry_()[-1] - - -class MovedPermanently(Retriable): - """ 301 Moved Permanently """ - pass - - -class Found(Retriable): - """ 302 Found """ - - pass - - -class SeeOther(Retriable): - """ 303 See Other """ - - def retry_method(self): - return 'GET' - - -class NotModified(ConnectionError): - """ 304 Not Modified """ - pass - - -class TemporaryRedirect(Retriable): - """ 307 Temporary Redirect """ - pass - - -class BadRequest(ConnectionError): - """ 400 Bad Request """ - pass - - -class Forbidden(ConnectionError): - """ 403 Forbidden """ - pass - - -class NotFound(ConnectionError): - """ 404 Not Found """ - pass - - -class Gone(ConnectionError): - """ 410 Gone """ - pass - - -class ServiceUnavailable(Retriable): - """ 503 Service Unavailable """ - def url(self): - return self.params._delegate.url - - -class GatewayTimeout(Retriable): - """ 504 Gateway Timeout """ - def url(self): - return self.params._delegate.url - - -class InternalServerError(ConnectionError): - """ 500 Internal Server Error """ - def __repr__(self): - try: - import simplejson - traceback = simplejson.loads(self.params.response_body) - except: - try: - from indra.base import llsd - traceback = llsd.parse(self.params.response_body) - except: - traceback = self.params.response_body - if isinstance(traceback, dict): - body = traceback - traceback = "Traceback (most recent call last):\n" - for frame in body['stack-trace']: - traceback += ' File "%s", line %s, in %s\n' % ( - frame['filename'], frame['lineno'], frame['method']) - for line in frame['code']: - if line['lineno'] == frame['lineno']: - traceback += ' %s' % (line['line'].lstrip(), ) - break - traceback += body['description'] - return "The server raised an exception from our request:\n%s %s\n%s %s\n%s" % ( - self.params.method, self.params.url, self.params.response.status, self.params.response.reason, traceback) - __str__ = __repr__ - - - -status_to_error_map = { - 202: Accepted, - 301: MovedPermanently, - 302: Found, - 303: SeeOther, - 304: NotModified, - 307: TemporaryRedirect, - 400: BadRequest, - 403: Forbidden, - 404: NotFound, - 410: Gone, - 500: InternalServerError, - 503: ServiceUnavailable, - 504: GatewayTimeout, -} - -scheme_to_factory_map = { - 'http': HttpClient, - 'https': HttpsClient, - 'file': FileScheme, -} - - -def make_connection(scheme, location, use_proxy): - """ Create a connection object to a host:port. - - @param scheme Protocol, scheme, whatever you want to call it. http, file, https are currently supported. - @param location Hostname and port number, formatted as host:port or http://host:port if you're so inclined. - @param use_proxy Connect to a proxy instead of the actual location. Uses environment variables to decide where the proxy actually lives. - """ - if use_proxy: - if "http_proxy" in os.environ: - location = os.environ["http_proxy"] - elif "ALL_PROXY" in os.environ: - location = os.environ["ALL_PROXY"] - else: - location = "localhost:3128" #default to local squid - - # run a little heuristic to see if location is an url, and if so parse out the hostpart - if location.startswith('http'): - _scheme, location, path, parameters, query, fragment = urlparse.urlparse(location) - - result = scheme_to_factory_map[scheme](location) - result.connect() - return result - - -def connect(url, use_proxy=False): - """ Create a connection object to the host specified in a url. Convenience function for make_connection.""" - scheme, location = urlparse.urlparse(url)[:2] - return make_connection(scheme, location, use_proxy) - - -def make_safe_loader(loader): - if not callable(loader): - return loader - def safe_loader(what): - try: - return loader(what) - except Exception: - import traceback - traceback.print_exc() - return None - return safe_loader - - -class HttpSuite(object): - def __init__(self, dumper, loader, fallback_content_type): - self.dumper = dumper - self.loader = loader - self.fallback_content_type = fallback_content_type - - def request_(self, params): - '''Make an http request to a url, for internal use mostly.''' - - params = _LocalParams(params, instance=self) - - (scheme, location, path, parameters, query, - fragment) = urlparse.urlparse(params.url) - - if params.use_proxy: - if scheme == 'file': - params.use_proxy = False - else: - params.headers['host'] = location - - if not params.use_proxy: - params.path = path - if query: - params.path += '?' + query - - params.orig_body = params.body - - if params.method in ('PUT', 'POST'): - if self.dumper is not None: - params.body = self.dumper(params.body) - # don't set content-length header because httplib does it - # for us in _send_request - else: - params.body = '' - - params.response, params.response_body = self._get_response_body(params) - response, body = params.response, params.response_body - - if self.loader is not None: - try: - body = make_safe_loader(self.loader(body)) - except KeyboardInterrupt: - raise - except Exception, e: - raise UnparseableResponse(self.loader, body, params.url) - - return response.status, response.msg, body - - def _check_status(self, params): - response = params.response - if response.status not in params.ok: - klass = status_to_error_map.get(response.status, ConnectionError) - raise klass(params) - - def _get_response_body(self, params): - connection = connect(params.url, params.use_proxy) - connection.request(params.method, params.path, params.body, - params.headers) - params.response = connection.getresponse() - params.response_body = params.response.read() - connection.close() - self._check_status(params) - - return params.response, params.response_body - - def request(self, params): - return self.request_(params)[-1] - - def head_(self, url, headers=None, use_proxy=False, ok=None, aux=None): - return self.request_(_Params(url, 'HEAD', headers=headers, - loader=self.loader, dumper=self.dumper, - use_proxy=use_proxy, ok=ok, aux=aux)) - - def head(self, *args, **kwargs): - return self.head_(*args, **kwargs)[-1] - - def get_(self, url, headers=None, use_proxy=False, ok=None, aux=None): - if headers is None: - headers = {} - headers['accept'] = self.fallback_content_type+';q=1,*/*;q=0' - return self.request_(_Params(url, 'GET', headers=headers, - loader=self.loader, dumper=self.dumper, - use_proxy=use_proxy, ok=ok, aux=aux)) - - def get(self, *args, **kwargs): - return self.get_(*args, **kwargs)[-1] - - def put_(self, url, data, headers=None, content_type=None, ok=None, - aux=None): - if headers is None: - headers = {} - if 'content-type' not in headers: - if content_type is None: - headers['content-type'] = self.fallback_content_type - else: - headers['content-type'] = content_type - headers['accept'] = headers['content-type']+';q=1,*/*;q=0' - return self.request_(_Params(url, 'PUT', body=data, headers=headers, - loader=self.loader, dumper=self.dumper, - ok=ok, aux=aux)) - - def put(self, *args, **kwargs): - return self.put_(*args, **kwargs)[-1] - - def delete_(self, url, ok=None, aux=None): - return self.request_(_Params(url, 'DELETE', loader=self.loader, - dumper=self.dumper, ok=ok, aux=aux)) - - def delete(self, *args, **kwargs): - return self.delete_(*args, **kwargs)[-1] - - def post_(self, url, data='', headers=None, content_type=None, ok=None, - aux=None): - if headers is None: - headers = {} - if 'content-type' not in headers: - if content_type is None: - headers['content-type'] = self.fallback_content_type - else: - headers['content-type'] = content_type - headers['accept'] = headers['content-type']+';q=1,*/*;q=0' - return self.request_(_Params(url, 'POST', body=data, - headers=headers, loader=self.loader, - dumper=self.dumper, ok=ok, aux=aux)) - - def post(self, *args, **kwargs): - return self.post_(*args, **kwargs)[-1] - - -def make_suite(dumper, loader, fallback_content_type): - """ Return a tuple of methods for making http requests with automatic bidirectional formatting with a particular content-type.""" - suite = HttpSuite(dumper, loader, fallback_content_type) - return suite.get, suite.put, suite.delete, suite.post - - -suite = HttpSuite(str, None, 'text/plain') -delete = suite.delete -delete_ = suite.delete_ -get = suite.get -get_ = suite.get_ -head = suite.head -head_ = suite.head_ -post = suite.post -post_ = suite.post_ -put = suite.put -put_ = suite.put_ -request = suite.request -request_ = suite.request_ diff --git a/eventlet/.svn/text-base/httpc_test.py.svn-base b/eventlet/.svn/text-base/httpc_test.py.svn-base deleted file mode 100644 index b0e14f0..0000000 --- a/eventlet/.svn/text-base/httpc_test.py.svn-base +++ /dev/null @@ -1,396 +0,0 @@ -"""\ -@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 -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 import api -from eventlet import httpc -from eventlet import httpd -from eventlet import processes -from eventlet import util -import time -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - - -util.wrap_socket_with_coroutine_socket() - - -from eventlet import tests - - -class Site(object): - def __init__(self): - self.stuff = {'hello': 'hello world'} - - def adapt(self, obj, req): - req.write(str(obj)) - - def handle_request(self, req): - return getattr(self, 'handle_%s' % req.method().lower())(req) - - -class BasicSite(Site): - def handle_get(self, req): - req.set_header('x-get', 'hello') - resp = StringIO() - path = req.path().lstrip('/') - try: - resp.write(self.stuff[path]) - except KeyError: - req.response(404, body='Not found') - return - for k,v in req.get_query_pairs(): - resp.write(k + '=' + v + '\n') - req.write(resp.getvalue()) - - def handle_head(self, req): - req.set_header('x-head', 'hello') - path = req.path().lstrip('/') - try: - req.write('') - except KeyError: - req.response(404, body='Not found') - - def handle_put(self, req): - req.set_header('x-put', 'hello') - path = req.path().lstrip('/') - if not path: - req.response(400, body='') - return - if path in self.stuff: - req.response(204) - else: - req.response(201) - self.stuff[path] = req.read_body() - req.write('') - - def handle_delete(self, req): - req.set_header('x-delete', 'hello') - path = req.path().lstrip('/') - if not path: - req.response(400, body='') - return - try: - del self.stuff[path] - req.response(204) - except KeyError: - req.response(404) - req.write('') - - def handle_post(self, req): - req.set_header('x-post', 'hello') - req.write(req.read_body()) - - -class TestBase(object): - site_class = BasicSite - - def base_url(self): - return 'http://localhost:31337/' - - def setUp(self): - self.logfile = StringIO() - self.victim = api.spawn(httpd.server, - api.tcp_listener(('0.0.0.0', 31337)), - self.site_class(), - log=self.logfile, - max_size=128) - - def tearDown(self): - api.kill(self.victim) - - -class TestHttpc(TestBase, tests.TestCase): - def test_get_bad_uri(self): - self.assertRaises(httpc.NotFound, - lambda: httpc.get(self.base_url() + 'b0gu5')) - - def test_get(self): - response = httpc.get(self.base_url() + 'hello') - self.assertEquals(response, 'hello world') - - def test_get_(self): - status, msg, body = httpc.get_(self.base_url() + 'hello') - self.assertEquals(status, 200) - self.assertEquals(msg.dict['x-get'], 'hello') - self.assertEquals(body, 'hello world') - - def test_get_query(self): - response = httpc.get(self.base_url() + 'hello?foo=bar&foo=quux') - self.assertEquals(response, 'hello worldfoo=bar\nfoo=quux\n') - - def test_head_(self): - status, msg, body = httpc.head_(self.base_url() + 'hello') - self.assertEquals(status, 200) - self.assertEquals(msg.dict['x-head'], 'hello') - self.assertEquals(body, '') - - def test_head(self): - self.assertEquals(httpc.head(self.base_url() + 'hello'), '') - - def test_post_(self): - data = 'qunge' - status, msg, body = httpc.post_(self.base_url() + '', data=data) - self.assertEquals(status, 200) - self.assertEquals(msg.dict['x-post'], 'hello') - self.assertEquals(body, data) - - def test_post(self): - data = 'qunge' - self.assertEquals(httpc.post(self.base_url() + '', data=data), - data) - - def test_put_bad_uri(self): - self.assertRaises( - httpc.BadRequest, - lambda: httpc.put(self.base_url() + '', data='')) - - def test_put_empty(self): - httpc.put(self.base_url() + 'empty', data='') - self.assertEquals(httpc.get(self.base_url() + 'empty'), '') - - def test_put_nonempty(self): - data = 'nonempty' - httpc.put(self.base_url() + 'nonempty', data=data) - self.assertEquals(httpc.get(self.base_url() + 'nonempty'), data) - - def test_put_01_create(self): - data = 'goodbye world' - status, msg, body = httpc.put_(self.base_url() + 'goodbye', - data=data) - self.assertEquals(status, 201) - self.assertEquals(msg.dict['x-put'], 'hello') - self.assertEquals(body, '') - self.assertEquals(httpc.get(self.base_url() + 'goodbye'), data) - - def test_put_02_modify(self): - self.test_put_01_create() - data = 'i really mean goodbye' - status = httpc.put_(self.base_url() + 'goodbye', data=data)[0] - self.assertEquals(status, 204) - self.assertEquals(httpc.get(self.base_url() + 'goodbye'), data) - - def test_delete_(self): - httpc.put(self.base_url() + 'killme', data='killme') - status, msg, body = httpc.delete_(self.base_url() + 'killme') - self.assertEquals(status, 204) - self.assertRaises( - httpc.NotFound, - lambda: httpc.get(self.base_url() + 'killme')) - - def test_delete(self): - httpc.put(self.base_url() + 'killme', data='killme') - self.assertEquals(httpc.delete(self.base_url() + 'killme'), '') - self.assertRaises( - httpc.NotFound, - lambda: httpc.get(self.base_url() + 'killme')) - - def test_delete_bad_uri(self): - self.assertRaises( - httpc.NotFound, - lambda: httpc.delete(self.base_url() + 'b0gu5')) - - -class RedirectSite(BasicSite): - response_code = 301 - - def handle_request(self, req): - if req.path().startswith('/redirect/'): - url = ('http://' + req.get_header('host') + - req.uri().replace('/redirect/', '/')) - req.response(self.response_code, headers={'location': url}, - body='') - return - return Site.handle_request(self, req) - -class Site301(RedirectSite): - pass - - -class Site302(BasicSite): - def handle_request(self, req): - if req.path().startswith('/expired/'): - url = ('http://' + req.get_header('host') + - req.uri().replace('/expired/', '/')) - headers = {'location': url, 'expires': '0'} - req.response(302, headers=headers, body='') - return - if req.path().startswith('/expires/'): - url = ('http://' + req.get_header('host') + - req.uri().replace('/expires/', '/')) - expires = time.time() + (100 * 24 * 60 * 60) - headers = {'location': url, 'expires': httpc.to_http_time(expires)} - req.response(302, headers=headers, body='') - return - return Site.handle_request(self, req) - - -class Site303(RedirectSite): - response_code = 303 - - -class Site307(RedirectSite): - response_code = 307 - - -class TestHttpc301(TestBase, tests.TestCase): - site_class = Site301 - - def base_url(self): - return 'http://localhost:31337/redirect/' - - def test_get(self): - try: - httpc.get(self.base_url() + 'hello') - self.assert_(False) - except httpc.MovedPermanently, err: - response = err.retry() - self.assertEquals(response, 'hello world') - - def test_post(self): - data = 'qunge' - try: - response = httpc.post(self.base_url() + '', data=data) - self.assert_(False) - except httpc.MovedPermanently, err: - response = err.retry() - self.assertEquals(response, data) - - -class TestHttpc302(TestBase, tests.TestCase): - site_class = Site302 - - def test_get_expired(self): - try: - httpc.get(self.base_url() + 'expired/hello') - self.assert_(False) - except httpc.Found, err: - response = err.retry() - self.assertEquals(response, 'hello world') - - def test_get_expires(self): - try: - httpc.get(self.base_url() + 'expires/hello') - self.assert_(False) - except httpc.Found, err: - response = err.retry() - self.assertEquals(response, 'hello world') - - -class TestHttpc303(TestBase, tests.TestCase): - site_class = Site303 - - def base_url(self): - return 'http://localhost:31337/redirect/' - - def test_post(self): - data = 'hello world' - try: - response = httpc.post(self.base_url() + 'hello', data=data) - self.assert_(False) - except httpc.SeeOther, err: - response = err.retry() - self.assertEquals(response, data) - - -class TestHttpc307(TestBase, tests.TestCase): - site_class = Site307 - - def base_url(self): - return 'http://localhost:31337/redirect/' - - def test_post(self): - data = 'hello world' - try: - response = httpc.post(self.base_url() + 'hello', data=data) - self.assert_(False) - except httpc.TemporaryRedirect, err: - response = err.retry() - self.assertEquals(response, data) - - -class Site500(BasicSite): - def handle_request(self, req): - req.response(500, body="screw you world") - return - - -class Site500(BasicSite): - def handle_request(self, req): - req.response(500, body="screw you world") - return - - -class TestHttpc500(TestBase, tests.TestCase): - site_class = Site500 - - def base_url(self): - return 'http://localhost:31337/' - - def test_get(self): - data = 'screw you world' - try: - response = httpc.get(self.base_url()) - self.fail() - except httpc.InternalServerError, e: - self.assertEquals(e.params.response_body, data) - self.assert_(str(e).count(data)) - self.assert_(repr(e).count(data)) - - -class Site504(BasicSite): - def handle_request(self, req): - req.response(504, body="screw you world") - - -class TestHttpc504(TestBase, tests.TestCase): - site_class = Site504 - - def base_url(self): - return 'http://localhost:31337/' - - def test_post(self): - # Simply ensure that a 504 status code results in a - # GatewayTimeout. Don't bother retrying. - data = 'hello world' - self.assertRaises(httpc.GatewayTimeout, - lambda: httpc.post(self.base_url(), data=data)) - - -class TestHttpTime(tests.TestCase): - rfc1123_time = 'Sun, 06 Nov 1994 08:49:37 GMT' - rfc850_time = 'Sunday, 06-Nov-94 08:49:37 GMT' - asctime_time = 'Sun Nov 6 08:49:37 1994' - secs_since_epoch = 784111777 - def test_to_http_time(self): - self.assertEqual(self.rfc1123_time, httpc.to_http_time(self.secs_since_epoch)) - - def test_from_http_time(self): - for formatted in (self.rfc1123_time, self.rfc850_time, self.asctime_time): - ticks = httpc.from_http_time(formatted, 0) - self.assertEqual(ticks, self.secs_since_epoch) - -if __name__ == '__main__': - tests.main() diff --git a/eventlet/.svn/text-base/httpd.py.svn-base b/eventlet/.svn/text-base/httpd.py.svn-base deleted file mode 100644 index 7d73756..0000000 --- a/eventlet/.svn/text-base/httpd.py.svn-base +++ /dev/null @@ -1,584 +0,0 @@ -"""\ -@file httpd.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 cgi -import errno -import socket -import sys -import time -import urllib -import socket -import traceback -import BaseHTTPServer - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -from eventlet import api -from eventlet import coros - - -DEFAULT_MAX_HTTP_VERSION = 'HTTP/1.1' - -USE_ACCESS_LOG = True - - -CONNECTION_CLOSED = (errno.EPIPE, errno.ECONNRESET) - - -class ErrorResponse(Exception): - _responses = BaseHTTPServer.BaseHTTPRequestHandler.responses - - def __init__(self, code, reason_phrase=None, headers=None, body=None): - Exception.__init__(self, reason_phrase) - self.code = code - if reason_phrase is None: - self.reason = self._responses[code][0] - else: - self.reason = reason_phrase - self.headers = headers - if body is None: - self.body = self._responses[code][1] - else: - self.body = body - - -class Request(object): - _method = None - _path = None - _responsecode = 200 - _reason_phrase = None - _request_started = False - _chunked = False - _producer_adapters = {} - depth = 0 - def __init__(self, protocol, method, path, headers): - self.context = {} - self.request_start_time = time.time() - self.site = protocol.server.site - self.protocol = protocol - self._method = method - if '?' in path: - self._path, self._query = path.split('?', 1) - self._query = self._query.replace('&', '&') - else: - self._path, self._query = path, None - self._incoming_headers = headers - self._outgoing_headers = dict() - - def response(self, code, reason_phrase=None, headers=None, body=None): - """Change the response code. This will not be sent until some - data is written; last call to this method wins. Default is - 200 if this is not called. - """ - self._responsecode = code - self._reason_phrase = reason_phrase - self.protocol.set_response_code(self, code, reason_phrase) - if headers is not None: - try: - headers = headers.iteritems() - except AttributeError: - pass - for key, value in headers: - self.set_header(key, value) - if body is not None: - self.write(body) - - def is_okay(self): - return 200 <= self._responsecode <= 299 - - def full_url(self): - path = self.path() - query = self.query() - if query: - path = path + '?' + query - - via = self.get_header('via', '') - if via.strip(): - next_part = iter(via.split()).next - - received_protocol = next_part() - received_by = next_part() - if received_by.endswith(','): - received_by = received_by[:-1] - else: - comment = '' - while not comment.endswith(','): - try: - comment += next_part() - except StopIteration: - comment += ',' - break - comment = comment[:-1] - else: - received_by = self.get_header('host') - - return '%s://%s%s' % (self.request_protocol(), received_by, path) - - def begin_response(self, length="-"): - """Begin the response, and return the initial response text - """ - self._request_started = True - request_time = time.time() - self.request_start_time - - code = self._responsecode - proto = self.protocol - - if USE_ACCESS_LOG: - proto.server.write_access_log_line( - proto.client_address[0], - time.strftime("%d/%b/%Y %H:%M:%S"), - proto.requestline, - code, - length, - request_time) - - if self._reason_phrase is not None: - message = self._reason_phrase.split("\n")[0] - elif code in proto.responses: - message = proto.responses[code][0] - else: - message = '' - if proto.request_version == 'HTTP/0.9': - return [] - - response_lines = proto.generate_status_line() - - if not self._outgoing_headers.has_key('connection'): - con = self.get_header('connection') - if con is None and proto.request_version == 'HTTP/1.0': - con = 'close' - if con is not None: - self.set_header('connection', con) - - for key, value in self._outgoing_headers.items(): - key = '-'.join([x.capitalize() for x in key.split('-')]) - response_lines.append("%s: %s" % (key, value)) - - response_lines.append("") - return response_lines - - def write(self, obj): - """Writes an arbitrary object to the response, using - the sitemap's adapt method to convert it to bytes. - """ - if isinstance(obj, str): - self._write_bytes(obj) - elif isinstance(obj, unicode): - # use utf8 encoding for now, *TODO support charset negotiation - # Content-Type: text/html; charset=utf-8 - ctype = self._outgoing_headers.get('content-type', 'text/html') - ctype = ctype + '; charset=utf-8' - self._outgoing_headers['content-type'] = ctype - self._write_bytes(obj.encode('utf8')) - else: - self.site.adapt(obj, self) - - def _write_bytes(self, data): - """Write all the data of the response. - Can be called just once. - """ - if self._request_started: - print "Request has already written a response:" - traceback.print_stack() - return - - self._outgoing_headers['content-length'] = len(data) - - response_lines = self.begin_response(len(data)) - response_lines.append(data) - self.protocol.wfile.write("\r\n".join(response_lines)) - if hasattr(self.protocol.wfile, 'flush'): - self.protocol.wfile.flush() - - def method(self): - return self._method - - def path(self): - return self._path - - def path_segments(self): - return [urllib.unquote_plus(x) for x in self._path.split('/')[1:]] - - def query(self): - return self._query - - def uri(self): - if self._query: - return '%s?%s' % ( - self._path, self._query) - return self._path - - def get_headers(self): - return self._incoming_headers - - def get_header(self, header_name, default=None): - return self.get_headers().get(header_name.lower(), default) - - def get_query_pairs(self): - if not hasattr(self, '_split_query'): - if self._query is None: - self._split_query = () - else: - spl = self._query.split('&') - spl = [x.split('=', 1) for x in spl if x] - self._split_query = [] - for query in spl: - if len(query) == 1: - key = query[0] - value = '' - else: - key, value = query - self._split_query.append((urllib.unquote_plus(key), urllib.unquote_plus(value))) - - return self._split_query - - def get_queries_generator(self, name): - """Generate all query parameters matching the given name. - """ - for key, value in self.get_query_pairs(): - if key == name or not name: - yield value - - get_queries = lambda self, name: list(self.get_queries_generator) - - def get_query(self, name, default=None): - try: - return self.get_queries_generator(name).next() - except StopIteration: - return default - - def get_arg_list(self, name): - return self.get_field_storage().getlist(name) - - def get_arg(self, name, default=None): - return self.get_field_storage().getfirst(name, default) - - def get_field_storage(self): - if not hasattr(self, '_field_storage'): - if self.method() == 'GET': - data = '' - if self._query: - data = self._query - else: - data = self.read_body() - fl = StringIO(data) - ## Allow our resource to provide the FieldStorage instance for - ## customization purposes. - headers = self.get_headers() - environ = dict( - REQUEST_METHOD='POST', - QUERY_STRING=self._query or '') - - self._field_storage = cgi.FieldStorage(fl, headers, environ=environ) - - return self._field_storage - - def set_header(self, key, value): - if key.lower() == 'connection' and value.lower() == 'close': - self.protocol.close_connection = 1 - self._outgoing_headers[key.lower()] = value - __setitem__ = set_header - - def get_outgoing_header(self, key): - return self._outgoing_headers[key.lower()] - - def has_outgoing_header(self, key): - return self._outgoing_headers.has_key(key.lower()) - - def socket(self): - return self.protocol.socket - - def error(self, response=None, body=None, log_traceback=True): - if log_traceback: - traceback.print_exc(file=self.log) - if response is None: - response = 500 - if body is None: - typ, val, tb = sys.exc_info() - body = dict(type=str(typ), error=True, reason=str(val)) - self.response(response) - if(type(body) is str and not self.response_written()): - self.write(body) - return - try: - produce(body, self) - except Exception, e: - traceback.print_exc(file=self.log) - if not self.response_written(): - self.write('Internal Server Error') - - def not_found(self): - self.error(404, 'Not Found\n', log_traceback=False) - - def raw_body(self): - if not hasattr(self, '_cached_body'): - self.read_body() - return self._cached_body - - def read_body(self): - """ Returns the string body that was read off the request, or - the empty string if there was no request body. - - Requires a content-length header. Caches the body so multiple - calls to read_body() are free. - """ - if not hasattr(self, '_cached_body'): - length = self.get_header('content-length') - if length: - length = int(length) - if length: - self._cached_body = self.protocol.rfile.read(length) - else: - self._cached_body = '' - return self._cached_body - - def parsed_body(self): - """ Returns the parsed version of the body, using the - content-type header to select from the parsers on the site - object. - - If no parser is found, returns the string body from - read_body(). Caches the parsed body so multiple calls to - parsed_body() are free. - """ - if not hasattr(self, '_cached_parsed_body'): - body = self.read_body() - if hasattr(self.site, 'parsers'): - parser = self.site.parsers.get( - self.get_header('content-type')) - if parser is not None: - body = parser(body) - self._cached_parsed_body = body - return self._cached_parsed_body - - def override_body(self, body): - if not hasattr(self, '_cached_parsed_body'): - self.read_body() ## Read and discard body - self._cached_parsed_body = body - - def response_written(self): - ## TODO change badly named variable - return self._request_started - - def request_version(self): - return self.protocol.request_version - - def request_protocol(self): - if self.protocol.socket.is_secure: - return "https" - return "http" - - def server_address(self): - return self.protocol.server.address - - def __repr__(self): - return "" % ( - getattr(self, '_method'), getattr(self, '_path')) - -DEFAULT_TIMEOUT = 300 - -# This value was chosen because apache 2 has a default limit of 8190. -# I believe that slightly smaller number is because apache does not -# count the \r\n. -MAX_REQUEST_LINE = 8192 - -class Timeout(RuntimeError): - pass - -class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): - def __init__(self, request, client_address, server): - self.socket = self.request = self.rfile = self.wfile = request - self.client_address = client_address - self.server = server - self.set_response_code(None, 200, None) - self.protocol_version = server.max_http_version - - def set_response_code(self, request, code, message): - self._code = code - if message is not None: - self._message = message.split("\n")[0] - elif code in self.responses: - self._message = self.responses[code][0] - else: - self._message = '' - - def generate_status_line(self): - return [ - "%s %d %s" % ( - self.protocol_version, self._code, self._message)] - - def write_bad_request(self, status, reason): - self.set_response_code(self, status, reason) - self.wfile.write(''.join(self.generate_status_line())) - self.wfile.write('\r\nServer: %s\r\n' % self.version_string()) - self.wfile.write('Date: %s\r\n' % self.date_time_string()) - self.wfile.write('Content-Length: 0\r\n\r\n') - - def handle(self): - self.close_connection = 0 - - timeout = DEFAULT_TIMEOUT - while not self.close_connection: - if timeout == 0: - break - cancel = api.exc_after(timeout, Timeout) - try: - self.raw_requestline = self.rfile.readline(MAX_REQUEST_LINE) - if self.raw_requestline is not None: - if len(self.raw_requestline) == MAX_REQUEST_LINE: - # Someone sent a request line which is too - # large. Be helpful and tell them. - self.write_bad_request(414, 'Request-URI Too Long') - self.close_connection = True - continue - except socket.error, e: - if e[0] in CONNECTION_CLOSED: - self.close_connection = True - cancel.cancel() - continue - except Timeout: - self.close_connection = True - continue - except Exception, e: - try: - if e[0][0][0].startswith('SSL'): - print "SSL Error:", e[0][0] - self.close_connection = True - cancel.cancel() - continue - except Exception, f: - print "Exception in ssl test:",f - pass - raise e - cancel.cancel() - - if not self.raw_requestline or not self.parse_request(): - self.close_connection = True - continue - - self.set_response_code(None, 200, None) - request = Request(self, self.command, self.path, self.headers) - request.set_header('Server', self.version_string()) - request.set_header('Date', self.date_time_string()) - try: - timeout = int(request.get_header('keep-alive', timeout)) - except TypeError, ValueError: - pass - - try: - try: - try: - self.server.site.handle_request(request) - except ErrorResponse, err: - request.response(code=err.code, - reason_phrase=err.reason, - headers=err.headers, - body=err.body) - finally: - # clean up any timers that might have been left around by the handling code - api.get_hub().runloop.cancel_timers(api.getcurrent()) - - # throw an exception if it failed to write a body - if not request.response_written(): - raise NotImplementedError("Handler failed to write response to request: %s" % request) - - if not hasattr(self, '_cached_body'): - try: - request.read_body() ## read & discard body - except: - pass - - except socket.error, e: - # Broken pipe, connection reset by peer - if e[0] in CONNECTION_CLOSED: - #print "Remote host closed connection before response could be sent" - pass - else: - raise - except Exception, e: - self.server.log_message("Exception caught in HttpRequest.handle():\n") - self.server.log_exception(*sys.exc_info()) - if not request.response_written(): - request.response(500) - request.write('Internal Server Error') - self.socket.close() - raise e # can't do a plain raise since exc_info might have been cleared - self.socket.close() - - -class Server(BaseHTTPServer.HTTPServer): - def __init__(self, socket, address, site, log, max_http_version=DEFAULT_MAX_HTTP_VERSION): - self.socket = socket - self.address = address - self.site = site - self.max_http_version = max_http_version - if log: - self.log = log - if hasattr(log, 'info'): - log.write = log.info - else: - self.log = self - - def write(self, something): - sys.stdout.write('%s' % (something, )); sys.stdout.flush() - - def log_message(self, message): - self.log.write(message) - - def log_exception(self, type, value, tb): - self.log.write(''.join(traceback.format_exception(type, value, tb))) - - def write_access_log_line(self, *args): - """Write a line to the access.log. Arguments: - client_address, date_time, requestline, code, size, request_time - """ - self.log.write( - '%s - - [%s] "%s" %s %s %.6f\n' % args) - - -def server(sock, site, log=None, max_size=512, serv=None, max_http_version=DEFAULT_MAX_HTTP_VERSION): - pool = coros.CoroutinePool(max_size=max_size) - if serv is None: - serv = Server(sock, sock.getsockname(), site, log, max_http_version=max_http_version) - try: - serv.log.write("httpd starting up on %s\n" % (sock.getsockname(), )) - while True: - try: - new_sock, address = sock.accept() - proto = HttpProtocol(new_sock, address, serv) - pool.execute_async(proto.handle) - api.sleep(0) # sleep to allow other coros to run - except KeyboardInterrupt: - api.get_hub().remove_descriptor(sock.fileno()) - serv.log.write("httpd exiting\n") - break - finally: - try: - sock.close() - except socket.error: - pass diff --git a/eventlet/.svn/text-base/httpd_test.py.svn-base b/eventlet/.svn/text-base/httpd_test.py.svn-base deleted file mode 100644 index e7e0fbc..0000000 --- a/eventlet/.svn/text-base/httpd_test.py.svn-base +++ /dev/null @@ -1,207 +0,0 @@ -"""\ -@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 -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 import api -from eventlet import httpd -from eventlet import processes -from eventlet import util - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - - -util.wrap_socket_with_coroutine_socket() - - -from eventlet import tests - - -class Site(object): - def handle_request(self, req): - path = req.path_segments() - if len(path) > 0 and path[0] == "notexist": - req.response(404, body='not found') - return - req.write('hello world') - - def adapt(self, obj, req): - req.write(str(obj)) - - -CONTENT_LENGTH = 'content-length' - - -""" -HTTP/1.1 200 OK -Date: foo -Content-length: 11 - -hello world -""" - -class ConnectionClosed(Exception): - pass - - -def read_http(sock): - response_line = sock.readline() - if not response_line: - raise ConnectionClosed - raw_headers = sock.readuntil('\r\n\r\n').strip() - #print "R", response_line, raw_headers - headers = dict() - for x in raw_headers.split('\r\n'): - #print "X", x - key, value = x.split(': ', 1) - headers[key.lower()] = value - - if CONTENT_LENGTH in headers: - num = int(headers[CONTENT_LENGTH]) - body = sock.read(num) - #print body - else: - body = None - - return response_line, headers, body - - -class TestHttpd(tests.TestCase): - mode = 'static' - def setUp(self): - self.logfile = StringIO() - self.site = Site() - self.killer = api.spawn( - httpd.server, api.tcp_listener(('0.0.0.0', 12346)), self.site, max_size=128, log=self.logfile) - - def tearDown(self): - api.kill(self.killer) - - def test_001_server(self): - sock = api.connect_tcp( - ('127.0.0.1', 12346)) - - sock.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n') - result = sock.read() - sock.close() - ## The server responds with the maximum version it supports - self.assert_(result.startswith('HTTP'), result) - self.assert_(result.endswith('hello world')) - - def test_002_keepalive(self): - sock = api.connect_tcp( - ('127.0.0.1', 12346)) - - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - read_http(sock) - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - read_http(sock) - sock.close() - - def test_003_passing_non_int_to_read(self): - # This should go in test_wrappedfd - sock = api.connect_tcp( - ('127.0.0.1', 12346)) - - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - cancel = api.exc_after(1, RuntimeError) - self.assertRaises(TypeError, sock.read, "This shouldn't work") - cancel.cancel() - sock.close() - - def test_004_close_keepalive(self): - sock = api.connect_tcp( - ('127.0.0.1', 12346)) - - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - read_http(sock) - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') - read_http(sock) - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - self.assertRaises(ConnectionClosed, read_http, sock) - sock.close() - - def skip_test_005_run_apachebench(self): - url = 'http://localhost:12346/' - # ab is apachebench - out = processes.Process(tests.find_command('ab'), - ['-c','64','-n','1024', '-k', url]) - print out.read() - - def test_006_reject_long_urls(self): - sock = api.connect_tcp( - ('127.0.0.1', 12346)) - path_parts = [] - for ii in range(3000): - path_parts.append('path') - path = '/'.join(path_parts) - request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path - sock.write(request) - result = sock.readline() - status = result.split(' ')[1] - self.assertEqual(status, '414') - sock.close() - - def test_007_get_arg(self): - # define a new handler that does a get_arg as well as a read_body - def new_handle_request(req): - a = req.get_arg('a') - body = req.read_body() - req.write('a is %s, body is %s' % (a, body)) - self.site.handle_request = new_handle_request - - sock = api.connect_tcp( - ('127.0.0.1', 12346)) - request = '\r\n'.join(( - 'POST /%s HTTP/1.0', - 'Host: localhost', - 'Content-Length: 3', - '', - 'a=a')) - sock.write(request) - - # send some junk after the actual request - sock.write('01234567890123456789') - reqline, headers, body = read_http(sock) - self.assertEqual(body, 'a is a, body is a=a') - sock.close() - - def test_008_correctresponse(self): - sock = api.connect_tcp( - ('127.0.0.1', 12346)) - - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - response_line_200,_,_ = read_http(sock) - sock.write('GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n') - response_line_404,_,_ = read_http(sock) - sock.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') - response_line_test,_,_ = read_http(sock) - self.assertEqual(response_line_200,response_line_test) - sock.close() - - -if __name__ == '__main__': - tests.main() diff --git a/eventlet/.svn/text-base/httpdate.py.svn-base b/eventlet/.svn/text-base/httpdate.py.svn-base deleted file mode 100644 index e1f81f3..0000000 --- a/eventlet/.svn/text-base/httpdate.py.svn-base +++ /dev/null @@ -1,39 +0,0 @@ -"""\ -@file httpdate.py -@author Donovan Preston - -Copyright (c) 2006-2007, Linden Research, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -""" - -import 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 - ) diff --git a/eventlet/.svn/text-base/jsonhttp.py.svn-base b/eventlet/.svn/text-base/jsonhttp.py.svn-base deleted file mode 100644 index 2fc0e54..0000000 --- a/eventlet/.svn/text-base/jsonhttp.py.svn-base +++ /dev/null @@ -1,40 +0,0 @@ -"""\ -@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 -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 import httpc - -import simplejson - - -def safe_load(what): - if not what: - return None - return simplejson.loads(what) - - -suite = httpc.HttpSuite(simplejson.dumps, safe_load, 'application/json') -head, get, put, delete, post = ( - suite.head, suite.get, suite.put, suite.delete, suite.post) -head_, get_, put_, delete_, post_ = ( - suite.head_, suite.get_, suite.put_, suite.delete_, suite.post_) diff --git a/eventlet/.svn/text-base/kqueuehub.py.svn-base b/eventlet/.svn/text-base/kqueuehub.py.svn-base deleted file mode 100644 index 595e7b9..0000000 --- a/eventlet/.svn/text-base/kqueuehub.py.svn-base +++ /dev/null @@ -1,219 +0,0 @@ -"""\ -@file kqueuehub.py -@author Donovan Preston - -Copyright (c) 2006-2007, Linden Research, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -""" - -import sys -import select -import kqueue -import traceback -from errno import EBADF - -from eventlet import greenlib -from eventlet.runloop import RunLoop, Timer - -import greenlet - -class Hub(object): - def __init__(self): - self.runloop = RunLoop(self.wait) - self.descriptor_queue = {} - self.descriptors = {} - self.greenlet = None - self.kfd = None - - def stop(self): - self.process_queue() - self.descriptors, self.descriptor_queue = self.descriptor_queue, {} - os.close(self.kfd) - self.kfd = None - self.runloop.abort() - if self.greenlet is not greenlet.getcurrent(): - self.switch() - - def schedule_call(self, *args, **kw): - return self.runloop.schedule_call(*args, **kw) - - def switch(self): - if not self.greenlet: - self.greenlet = greenlib.tracked_greenlet() - args = ((self.runloop.run,),) - else: - args = () - try: - greenlet.getcurrent().parent = self.greenlet - except ValueError: - pass - return greenlib.switch(self.greenlet, *args) - - def add_descriptor(self, fileno, read=None, write=None, exc=None): - self.descriptor_queue[fileno] = read, write, exc - - def remove_descriptor(self, fileno): - self.descriptor_queue[fileno] = None, None, None - - def exc_descriptor(self, fileno): - # We must handle two cases here, the descriptor - # may be changing or removing its exc handler - # in the queue, or it may be waiting on the queue. - exc = None - try: - exc = self.descriptor_queue[fileno][2] - except KeyError: - try: - exc = self.descriptors[fileno][2] - except KeyError: - pass - if exc is not None: - try: - exc() - except self.runloop.SYSTEM_EXCEPTIONS: - self.squelch_exception(fileno, sys.exc_info()) - - def squelch_exception(self, fileno, exc_info): - traceback.print_exception(*exc_info) - print >>sys.stderr, "Removing descriptor: %r" % (fileno,) - try: - self.remove_descriptor(fileno) - except Exception, e: - print >>sys.stderr, "Exception while removing descriptor! %r" % (e,) - - def process_queue(self): - if self.kfd is None: - self.kfd = kqueue.kqueue() - d = self.descriptors - - E_R = kqueue.EVFILT_READ - E_W = kqueue.EVFILT_WRITE - E = kqueue.Event - E_ADD = kqueue.EV_ADD - E_DEL = kqueue.EV_DELETE - - kevent = kqueue.kevent - kfd = self.kfd - for fileno, rwe in self.descriptor_queue.iteritems(): - read, write, exc = rwe - if read is None and write is None and exc is None: - try: - read, write, exc = d.pop(fileno) - except KeyError: - pass - else: - l = [] - if read is not None: - l.append(E(fileno, E_R, E_DEL)) - if write is not None: - l.append(E(fileno, E_W, E_DEL)) - if l: - try: - kevent(kfd, l, 0, 0) - except OSError, e: - if e[0] != EBADF: - raise - else: - l = [] - try: - oldr, oldw, olde = d[fileno] - except KeyError: - pass - else: - if oldr is not None: - if read is None: - l.append(E(fileno, E_R, E_DEL)) - else: - read = None - if oldw is not None: - if write is None: - l.append(E(fileno, E_W, E_DEL)) - else: - write = None - if read is not None: - l.append(E(fileno, E_R, E_ADD)) - if write is not None: - l.append(E(fileno, E_W, E_ADD)) - if l: - try: - kevent(kfd, l, 0, 0) - except OSError, e: - if e[0] != EBADF: - raise - try: - del d[fileno] - except KeyError: - pass - if exc is not None: - try: - exc(fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) - continue - d[fileno] = rwe - self.descriptor_queue.clear() - - def wait(self, seconds=None): - - self.process_queue() - - if seconds is not None: - seconds *= 1000000000.0 - dct = self.descriptors - events = kqueue.kevent(self.kfd, [], len(dct), seconds) - - SYSTEM_EXCEPTIONS = self.runloop.SYSTEM_EXCEPTIONS - - E_R = kqueue.EVFILT_READ - E_W = kqueue.EVFILT_WRITE - E_EOF = kqueue.EV_EOF - - for e in events: - fileno = e.ident - event = e.filter - - try: - read, write, exc = dct[fileno] - except KeyError: - continue - - if read is not None and event == E_R: - try: - read(fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) - elif exc is not None and e.fflags & E_EOF: - try: - exc(fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) - - if write is not None and event == E_W: - try: - write(fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) diff --git a/eventlet/.svn/text-base/logutil.py.svn-base b/eventlet/.svn/text-base/logutil.py.svn-base deleted file mode 100644 index 0885042..0000000 --- a/eventlet/.svn/text-base/logutil.py.svn-base +++ /dev/null @@ -1,112 +0,0 @@ -"""\ -@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 -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 syslog -import logging - - -def file_logger(filename): - """Create a logger. This sucks, the logging module sucks, but - it'll do for now. - """ - handler = logging.FileHandler(filename) - formatter = logging.Formatter() - handler.setFormatter(formatter) - log = logging.getLogger(filename) - log.addHandler(handler) - log.setLevel(logging.DEBUG) - return log, handler - - -def stream_logger(stream): - """Create a logger. This sucks.""" - handler = logging.StreamHandler(stream) - formatter = logging.Formatter() - handler.setFormatter(formatter) - log = logging.getLogger() - log.addHandler(handler) - log.setLevel(logging.DEBUG) - return log, handler - - -class LineLogger(object): - towrite = '' - def __init__(self, emit=None): - if emit is not None: - self.emit = emit - - def write(self, stuff): - self.towrite += stuff - if '\n' in self.towrite: - self.flush() - - def flush(self): - try: - newline = self.towrite.index('\n') - except ValueError: - newline = len(self.towrite) - while True: - self.emit(self.towrite[:newline]) - self.towrite = self.towrite[newline+1:] - try: - newline = self.towrite.index('\n') - except ValueError: - break - - def close(self): - pass - - def emit(self, *args): - pass - - -class SysLogger(LineLogger): - """A file-like object which writes to syslog. Can be inserted - as sys.stdin and sys.stderr to have logging output redirected - to syslog. - """ - def __init__(self, priority): - self.priority = priority - - def emit(self, line): - syslog.syslog(self.priority, line) - - -class TeeLogger(LineLogger): - def __init__(self, one, two): - self.one, self.two = one, two - - def emit(self, line): - self.one.emit(line) - self.two.emit(line) - - -class FileLogger(LineLogger): - def __init__(self, file): - self.file = file - - def emit(self, line): - self.file.write(line + '\n') - self.file.flush() - diff --git a/eventlet/.svn/text-base/pollhub.py.svn-base b/eventlet/.svn/text-base/pollhub.py.svn-base deleted file mode 100644 index 0540837..0000000 --- a/eventlet/.svn/text-base/pollhub.py.svn-base +++ /dev/null @@ -1,189 +0,0 @@ -"""\ -@file pollhub.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. -""" - -import sys -import select -import socket -import errno -import traceback -from time import sleep - -from eventlet import greenlib -from eventlet.runloop import RunLoop, Timer - -import greenlet - -EXC_MASK = select.POLLERR | select.POLLHUP | select.POLLNVAL -READ_MASK = select.POLLIN -WRITE_MASK = select.POLLOUT - -class Hub(object): - def __init__(self): - self.runloop = RunLoop(self.wait) - self.descriptor_queue = {} - self.descriptors = {} - self.greenlet = None - self.poll = select.poll() - - def stop(self): - self.process_queue() - self.runloop.abort() - if self.greenlet is not greenlet.getcurrent(): - self.switch() - - def schedule_call(self, *args, **kw): - return self.runloop.schedule_call(*args, **kw) - - def switch(self): - if not self.greenlet: - self.greenlet = greenlib.tracked_greenlet() - args = ((self.runloop.run,),) - else: - args = () - try: - greenlet.getcurrent().parent = self.greenlet - except ValueError: - pass - return greenlib.switch(self.greenlet, *args) - - def add_descriptor(self, fileno, read=None, write=None, exc=None): - if fileno in self.descriptor_queue: - oread, owrite, oexc = self.descriptor_queue[fileno] - read, write, exc = read or oread, write or owrite, exc or oexc - self.descriptor_queue[fileno] = read, write, exc - - def remove_descriptor(self, fileno): - self.descriptor_queue[fileno] = None, None, None - - def exc_descriptor(self, fileno): - # We must handle two cases here, the descriptor - # may be changing or removing its exc handler - # in the queue, or it may be waiting on the queue. - exc = None - try: - exc = self.descriptor_queue[fileno][2] - except KeyError: - try: - exc = self.descriptors[fileno][2] - except KeyError: - pass - if exc is not None: - try: - exc(fileno) - except self.runloop.SYSTEM_EXCEPTIONS: - self.squelch_exception(fileno, sys.exc_info()) - - def squelch_exception(self, fileno, exc_info): - traceback.print_exception(*exc_info) - print >>sys.stderr, "Removing descriptor: %r" % (fileno,) - try: - self.remove_descriptor(fileno) - except Exception, e: - print >>sys.stderr, "Exception while removing descriptor! %r" % (e,) - - def process_queue(self): - d = self.descriptors - reg = self.poll.register - unreg = self.poll.unregister - rm = READ_MASK - wm = WRITE_MASK - for fileno, rwe in self.descriptor_queue.iteritems(): - read, write, exc = rwe - if read is None and write is None and exc is None: - try: - del d[fileno] - except KeyError: - pass - else: - try: - unreg(fileno) - except socket.error: -# print "squelched socket err on unreg", fileno - pass - else: - mask = 0 - if read is not None: - mask |= rm - if write is not None: - mask |= wm - oldmask = 0 - try: - oldr, oldw, olde = d[fileno] - except KeyError: - pass - else: - if oldr is not None: - oldmask |= rm - if oldw is not None: - oldmask |= wm - if mask != oldmask: - reg(fileno, mask) - d[fileno] = rwe - self.descriptor_queue.clear() - - def wait(self, seconds=None): - self.process_queue() - - if not self.descriptors: - if seconds: - sleep(seconds) - return - try: - presult = self.poll.poll(seconds * 1000.0) - except select.error, e: - if e.args[0] == errno.EINTR: - return - raise - SYSTEM_EXCEPTIONS = self.runloop.SYSTEM_EXCEPTIONS - dct = self.descriptors - - for fileno, event in presult: - try: - read, write, exc = dct[fileno] - except KeyError: - continue - - if read is not None and event & READ_MASK: - try: - read(fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) - elif exc is not None and event & EXC_MASK: - try: - exc(fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) - - if write is not None and event & WRITE_MASK: - try: - write(fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) diff --git a/eventlet/.svn/text-base/pools.py.svn-base b/eventlet/.svn/text-base/pools.py.svn-base deleted file mode 100644 index 5e89dc4..0000000 --- a/eventlet/.svn/text-base/pools.py.svn-base +++ /dev/null @@ -1,184 +0,0 @@ -"""\ -@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 -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 collections -import os -import socket - -from eventlet import api -from eventlet import channel -from eventlet import httpc - -class FanFailed(RuntimeError): - pass - - -class SomeFailed(FanFailed): - pass - - -class AllFailed(FanFailed): - pass - - -class Pool(object): - """ - When using the pool, if you do a get, you should ALWAYS do a put. - The pattern is: - - thing = self.pool.get() - try: - # do stuff - finally: - self.pool.put(thing) - """ - def __init__(self, min_size=0, max_size=4): - self.min_size = min_size - self.max_size = max_size - self.current_size = 0 - self.channel = channel.channel() - self.free_items = collections.deque() - for x in range(min_size): - self.current_size += 1 - self.free_items.append(self.create()) - - def get(self): - """Return an item from the pool, when one is available - """ - if self.free_items: - return self.free_items.popleft() - if self.current_size < self.max_size: - self.current_size += 1 - return self.create() - return self.channel.receive() - - def put(self, item): - """Put an item back into the pool, when done - """ - if self.current_size > self.max_size: - self.current_size -= 1 - return - - if self.channel.balance < 0: - self.channel.send(item) - else: - self.free_items.append(item) - - def resize(self, new_size): - """Resize the pool - """ - self.max_size = new_size - - def free(self): - """Return the number of free items in the pool. - """ - return len(self.free_items) + self.max_size - self.current_size - - def waiting(self): - """Return the number of routines waiting for a pool item. - """ - if self.channel.balance < 0: - return -self.channel.balance - return 0 - - def create(self): - """Generate a new pool item - """ - raise NotImplementedError("Implement in subclass") - - def fan(self, block, input_list): - chan = channel.channel() - results = [] - exceptional_results = 0 - for index, input_item in enumerate(input_list): - pool_item = self.get() - - ## Fan out - api.spawn( - self._invoke, block, pool_item, input_item, index, chan) - - ## Fan back in - for i in range(len(input_list)): - ## Wait for all guys to send to the queue - index, value = chan.receive() - if isinstance(value, Exception): - exceptional_results += 1 - results.append((index, value)) - - results.sort() - results = [value for index, value in results] - - if exceptional_results: - if exceptional_results == len(results): - raise AllFailed(results) - raise SomeFailed(results) - return results - - def _invoke(self, block, pool_item, input_item, index, chan): - try: - result = block(pool_item, input_item) - except Exception, e: - self.put(pool_item) - chan.send((index, e)) - return - self.put(pool_item) - chan.send((index, result)) - - -class Token(object): - pass - - -class TokenPool(Pool): - """A pool which gives out tokens, an object indicating that - the person who holds the token has a right to consume some - limited resource. - """ - def create(self): - return Token() - - -class ConnectionPool(Pool): - """A Pool which can limit the number of concurrent http operations - being made to a given server. - - *NOTE: *TODO: - - This does NOT currently keep sockets open. It discards the created - http object when it is put back in the pool. This is because we do - not yet have a combination of http clients and servers which can work - together to do HTTP keepalive sockets without errors. - """ - def __init__(self, proto, netloc, use_proxy, min_size=0, max_size=4): - self.proto = proto - self.netloc = netloc - self.use_proxy = use_proxy - Pool.__init__(self, min_size, max_size) - - def create(self): - return httpc.make_connection(self.proto, self.netloc, self.use_proxy) - - def put(self, item): - ## Discard item, create a new connection for the pool - Pool.put(self, self.create()) diff --git a/eventlet/.svn/text-base/pools_test.py.svn-base b/eventlet/.svn/text-base/pools_test.py.svn-base deleted file mode 100644 index e604bc1..0000000 --- a/eventlet/.svn/text-base/pools_test.py.svn-base +++ /dev/null @@ -1,179 +0,0 @@ -"""\ -@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 -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 unittest - -from eventlet import api -from eventlet import channel -from eventlet import pools - - -class IntPool(pools.Pool): - def create(self): - self.current_integer = getattr(self, 'current_integer', 0) + 1 - return self.current_integer - - -class TestIntPool(unittest.TestCase): - mode = 'static' - def setUp(self): - self.pool = IntPool(min_size=0, max_size=4) - - def test_integers(self): - # Do not actually use this pattern in your code. The pool will be - # exhausted, and unrestoreable. - # If you do a get, you should ALWAYS do a put, probably like this: - # try: - # thing = self.pool.get() - # # do stuff - # finally: - # self.pool.put(thing) - - # with self.pool.some_api_name() as thing: - # # do stuff - self.assertEquals(self.pool.get(), 1) - self.assertEquals(self.pool.get(), 2) - self.assertEquals(self.pool.get(), 3) - self.assertEquals(self.pool.get(), 4) - - def test_free(self): - self.assertEquals(self.pool.free(), 4) - gotten = self.pool.get() - self.assertEquals(self.pool.free(), 3) - self.pool.put(gotten) - self.assertEquals(self.pool.free(), 4) - - def test_exhaustion(self): - waiter = channel.channel() - def consumer(): - gotten = None - try: - gotten = self.pool.get() - finally: - waiter.send(gotten) - - api.spawn(consumer) - - one, two, three, four = ( - self.pool.get(), self.pool.get(), self.pool.get(), self.pool.get()) - self.assertEquals(self.pool.free(), 0) - - # Let consumer run; nothing will be in the pool, so he will wait - api.sleep(0) - - # Wake consumer - self.pool.put(one) - - # wait for the consumer - self.assertEquals(waiter.receive(), one) - - def test_blocks_on_pool(self): - waiter = channel.channel() - def greedy(): - self.pool.get() - self.pool.get() - self.pool.get() - self.pool.get() - # No one should be waiting yet. - self.assertEquals(self.pool.waiting(), 0) - # The call to the next get will unschedule this routine. - self.pool.get() - # So this send should never be called. - waiter.send('Failed!') - - killable = api.spawn(greedy) - - # no one should be waiting yet. - self.assertEquals(self.pool.waiting(), 0) - - ## Wait for greedy - api.sleep(0) - - ## Greedy should be blocking on the last get - self.assertEquals(self.pool.waiting(), 1) - - ## Send will never be called, so balance should be 0. - self.assertEquals(waiter.balance, 0) - - api.kill(killable) - - -class TestAbstract(unittest.TestCase): - mode = 'static' - def test_abstract(self): - ## Going for 100% coverage here - ## A Pool cannot be used without overriding create() - pool = pools.Pool() - self.assertRaises(NotImplementedError, pool.get) - - -class TestIntPool2(unittest.TestCase): - mode = 'static' - def setUp(self): - self.pool = IntPool(min_size=3, max_size=3) - - def test_something(self): - self.assertEquals(len(self.pool.free_items), 3) - ## Cover the clause in get where we get from the free list instead of creating - ## an item on get - gotten = self.pool.get() - self.assertEquals(gotten, 1) - - -ALWAYS = RuntimeError('I always fail') -SOMETIMES = RuntimeError('I fail half the time') - - -class TestFan(unittest.TestCase): - mode = 'static' - def setUp(self): - self.pool = IntPool(max_size=2) - - def test_with_list(self): - list_of_input = ['agent-one', 'agent-two', 'agent-three'] - - def my_callable(pool_item, next_thing): - ## Do some "blocking" (yielding) thing - api.sleep(0.01) - return next_thing - - output = self.pool.fan(my_callable, list_of_input) - self.assertEquals(list_of_input, output) - - def test_all_fail(self): - def my_failure(pool_item, next_thing): - raise ALWAYS - self.assertRaises(pools.AllFailed, self.pool.fan, my_failure, range(4)) - - def test_some_fail(self): - def my_failing_callable(pool_item, next_thing): - if next_thing % 2: - raise SOMETIMES - return next_thing - self.assertRaises(pools.SomeFailed, self.pool.fan, my_failing_callable, range(4)) - - -if __name__ == '__main__': - unittest.main() - diff --git a/eventlet/.svn/text-base/processes.py.svn-base b/eventlet/.svn/text-base/processes.py.svn-base deleted file mode 100644 index c51d1e7..0000000 --- a/eventlet/.svn/text-base/processes.py.svn-base +++ /dev/null @@ -1,141 +0,0 @@ -"""\ -@file processes.py - -Copyright (c) 2006-2007, Linden Research, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -""" - - -import os -import popen2 -import signal - - -from eventlet import util, pools -from eventlet import wrappedfd - -class DeadProcess(RuntimeError): - pass - - -class Process(object): - process_number = 0 - def __init__(self, command, args, dead_callback=lambda:None): - self.process_number = self.process_number + 1 - Process.process_number = self.process_number - self.command = command - self.args = args - self._dead_callback = dead_callback - self.run() - - def run(self): - self.dead = False - self.started = False - self.popen4 = None - - ## We use popen4 so that read() will read from either stdout or stderr - self.popen4 = popen2.Popen4([self.command] + self.args) - child_stdout_stderr = self.popen4.fromchild - child_stdin = self.popen4.tochild - util.set_nonblocking(child_stdout_stderr) - util.set_nonblocking(child_stdin) - self.child_stdout_stderr = wrappedfd.wrapped_file(child_stdout_stderr) - self.child_stdout_stderr.newlines = '\n' # the default is \r\n, which aren't sent over pipes - self.child_stdin = wrappedfd.wrapped_file(child_stdin) - self.child_stdin.newlines = '\n' - - self.sendall = self.child_stdin.write - self.send = self.child_stdin.write - self.recv = self.child_stdout_stderr.read - self.readline = self.child_stdout_stderr.readline - - def dead_callback(self): - self.dead = True - if self._dead_callback: - self._dead_callback() - - def makefile(self, mode, *arg): - if mode.startswith('r'): - return self.child_stdout_stderr - if mode.startswith('w'): - return self.child_stdin - raise RuntimeError("Unknown mode", mode) - - def read(self, amount=None): - result = self.child_stdout_stderr.read(amount) - if result == '': - # This process is dead. - self.dead_callback() - raise DeadProcess - return result - - def write(self, stuff): - written = self.child_stdin.send(stuff) - try: - self.child_stdin.flush() - except ValueError, e: - ## File was closed - assert str(e) == 'I/O operation on closed file' - if written == 0: - self.dead_callback() - raise DeadProcess - - def flush(self): - self.child_stdin.flush() - - def close(self): - self.child_stdout_stderr.close() - self.child_stdin.close() - self.dead_callback() - - def close_stdin(self): - self.child_stdin.close() - - def kill(self, sig=None): - if sig == None: - sig = signal.SIGTERM - os.kill(self.popen4.pid, sig) - - def getpid(self): - return self.popen4.pid - - -class ProcessPool(pools.Pool): - def __init__(self, command, args=None, min_size=0, max_size=4): - """@param command the command to run - """ - self.command = command - if args is None: - args = [] - self.args = args - pools.Pool.__init__(self, min_size, max_size) - - def create(self): - """Generate a process - """ - def dead_callback(): - self.current_size -= 1 - return Process(self.command, self.args, dead_callback) - - def put(self, item): - if not item.dead: - if item.popen4.poll() != -1: - item.dead_callback() - else: - pools.Pool.put(self, item) diff --git a/eventlet/.svn/text-base/processes_test.py.svn-base b/eventlet/.svn/text-base/processes_test.py.svn-base deleted file mode 100644 index 2cbab7d..0000000 --- a/eventlet/.svn/text-base/processes_test.py.svn-base +++ /dev/null @@ -1,134 +0,0 @@ -"""\ -@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. -""" -from eventlet import tests -from eventlet import api -from eventlet import channel -from eventlet import processes - -class TestEchoPool(tests.TestCase): - mode = 'static' - def setUp(self): - self.pool = processes.ProcessPool('echo', ["hello"]) - - def test_echo(self): - result = None - - proc = self.pool.get() - try: - result = proc.read() - finally: - self.pool.put(proc) - self.assertEquals(result, 'hello\n') - - def test_read_eof(self): - proc = self.pool.get() - try: - proc.read() - self.assertRaises(processes.DeadProcess, proc.read) - finally: - self.pool.put(proc) - - -class TestCatPool(tests.TestCase): - mode = 'static' - def setUp(self): - self.pool = processes.ProcessPool('cat') - - def test_cat(self): - result = None - - proc = self.pool.get() - try: - proc.write('goodbye') - proc.close_stdin() - result = proc.read() - finally: - self.pool.put(proc) - - self.assertEquals(result, 'goodbye') - - def test_write_to_dead(self): - result = None - - proc = self.pool.get() - try: - proc.write('goodbye') - proc.close_stdin() - result = proc.read() - self.assertRaises(processes.DeadProcess, proc.write, 'foo') - finally: - self.pool.put(proc) - - def test_close(self): - result = None - - proc = self.pool.get() - try: - proc.write('hello') - proc.close() - self.assertRaises(processes.DeadProcess, proc.write, 'goodbye') - finally: - self.pool.put(proc) - - -class TestDyingProcessesLeavePool(tests.TestCase): - mode = 'static' - def setUp(self): - self.pool = processes.ProcessPool('echo', ['hello'], max_size=1) - - def test_dead_process_not_inserted_into_pool(self): - proc = self.pool.get() - try: - result = proc.read() - self.assertEquals(result, 'hello\n') - finally: - self.pool.put(proc) - proc2 = self.pool.get() - self.assert_(proc is not proc2) - - -class TestProcessLivesForever(tests.TestCase): - mode = 'static' - def setUp(self): - self.pool = processes.ProcessPool('yes', max_size=1) - - def test_reading_twice_from_same_process(self): - proc = self.pool.get() - try: - result = proc.read(2) - self.assertEquals(result, 'y\n') - finally: - self.pool.put(proc) - - proc2 = self.pool.get() - self.assert_(proc is proc2) - try: - result = proc2.read(2) - self.assertEquals(result, 'y\n') - finally: - self.pool.put(proc2) - - -if __name__ == '__main__': - tests.main() diff --git a/eventlet/.svn/text-base/pylibsupport.py.svn-base b/eventlet/.svn/text-base/pylibsupport.py.svn-base deleted file mode 100644 index 1378e7a..0000000 --- a/eventlet/.svn/text-base/pylibsupport.py.svn-base +++ /dev/null @@ -1,42 +0,0 @@ -"""\ -@file pylibsupport.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. -""" - - -from py.magic import greenlet - - -import sys -import types - - -def emulate(): - module = types.ModuleType('greenlet') - sys.modules['greenlet'] = module - module.greenlet = greenlet - module.getcurrent = greenlet.getcurrent - module.GreenletExit = greenlet.GreenletExit - - - diff --git a/eventlet/.svn/text-base/runloop.py.svn-base b/eventlet/.svn/text-base/runloop.py.svn-base deleted file mode 100644 index 3fde1a4..0000000 --- a/eventlet/.svn/text-base/runloop.py.svn-base +++ /dev/null @@ -1,228 +0,0 @@ -"""\ -@file runloop.py -@author Bob Ippolito - -Defines the core eventlet runloop. The runloop keeps track of scheduled -events and observers which watch for specific portions of the runloop to -be executed. - -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. -""" - -import time -import bisect -import sys -import traceback - -import greenlet - -from eventlet.timer import Timer - - -class RunLoop(object): - SYSTEM_EXCEPTIONS = (KeyboardInterrupt, SystemExit) - - def __init__(self, wait=None, clock=None): - if clock is None: - clock = self.default_clock() - self.clock = clock - if wait is None: - wait = self.default_wait - self.wait = wait - self.stopping = False - self.running = False - self.timers = [] - self.timers_by_greenlet = {} - self.next_timers = [] - self.observers = {} - self.observer_modes = { - 'entry': [], - 'before_timers': [], - 'before_waiting': [], - 'after_waiting': [], - 'exit': [], - } - - def default_wait(self, time): - return None - - def default_clock(self): - return time.time - - def default_sleep(self): - return 60.0 - - def sleep_until(self): - t = self.timers - if not t: - return None - return t[0][0] - - def run(self): - """Run the runloop until abort is called. - """ - if self.running: - raise RuntimeError("Already running!") - try: - self.running = True - self.stopping = False - self.fire_observers('entry') - while not self.stopping: - self.prepare_timers() - self.fire_observers('before_timers') - self.fire_timers(self.clock()) - self.prepare_timers() - wakeup_when = self.sleep_until() - if wakeup_when is None: - sleep_time = self.default_sleep() - else: - sleep_time = wakeup_when - self.clock() - if sleep_time > 0: - self.fire_observers('before_waiting') - self.wait(sleep_time) - self.fire_observers('after_waiting') - else: - self.wait(0) - else: - del self.timers[:] - del self.next_timers[:] - self.fire_observers('exit') - finally: - self.running = False - self.stopping = False - - def abort(self): - """Stop the runloop. If run is executing, it will exit after completing - the next runloop iteration. - """ - if self.running: - self.stopping = True - - def add_observer(self, observer, *modes): - """Add an event observer to this runloop with the given modes. - Valid modes are: - entry: The runloop is being entered. - before_timers: Before the expired timers for this iteration are executed. - before_waiting: Before waiting for the calculated wait_time - where nothing will happen. - after_waiting: After waiting, immediately before starting the top of the - runloop again. - exit: The runloop is exiting. - - If no mode is passed or mode is all, the observer will be fired for every - event type. - """ - if not modes or modes == ('all',): - modes = tuple(self.observer_modes) - self.observers[observer] = modes - for mode in modes: - self.observer_modes[mode].append(observer) - - def remove_observer(self, observer): - """Remove a previously registered observer from all event types. - """ - for mode in self.observers.pop(observer, ()): - self.observer_modes[mode].remove(observer) - - def squelch_observer_exception(self, observer, exc_info): - traceback.print_exception(*exc_info) - print >>sys.stderr, "Removing observer: %r" % (observer,) - self.remove_observer(observer) - - def fire_observers(self, activity): - for observer in self.observer_modes[activity]: - try: - observer(self, activity) - except self.SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_observer_exception(observer, sys.exc_info()) - - def squelch_timer_exception(self, timer, exc_info): - traceback.print_exception(*exc_info) - print >>sys.stderr, "Timer raised: %r" % (timer,) - - def _add_absolute_timer(self, when, info): - # the 0 placeholder makes it easy to bisect_right using (now, 1) - self.next_timers.append((when, 0, info)) - - def add_timer(self, timer): - scheduled_time = self.clock() + timer.seconds - self._add_absolute_timer(scheduled_time, timer) - current_greenlet = greenlet.getcurrent() - if current_greenlet not in self.timers_by_greenlet: - self.timers_by_greenlet[current_greenlet] = {} - self.timers_by_greenlet[current_greenlet][timer] = True - timer.greenlet = current_greenlet - return scheduled_time - - - def prepare_timers(self): - ins = bisect.insort_right - t = self.timers - for item in self.next_timers: - ins(t, item) - del self.next_timers[:] - - def schedule_call(self, seconds, cb, *args, **kw): - """Schedule a callable to be called after 'seconds' seconds have - elapsed. - seconds: The number of seconds to wait. - cb: The callable to call after the given time. - *args: Arguments to pass to the callable when called. - **kw: Keyword arguments to pass to the callable when called. - """ - t = Timer(seconds, cb, *args, **kw) - self.add_timer(t) - return t - - def fire_timers(self, when): - t = self.timers - last = bisect.bisect_right(t, (when, 1)) - i = 0 - for i in xrange(last): - timer = t[i][2] - try: - try: - timer() - except self.SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_timer_exception(timer, sys.exc_info()) - finally: - try: - del self.timers_by_greenlet[timer.greenlet][timer] - except KeyError: - pass - del t[:last] - - def cancel_timers(self, greenlet): - if greenlet not in self.timers_by_greenlet: - return - for timer in self.timers_by_greenlet[greenlet]: - if not timer.cancelled and timer.seconds: - ## If timer.seconds is 0, this isn't a timer, it's - ## actually eventlet's silly way of specifying whether - ## a coroutine is "ready to run" or not. - timer.cancel() - print 'Runloop cancelling left-over timer %s' % timer - del self.timers_by_greenlet[greenlet] - diff --git a/eventlet/.svn/text-base/runloop_test.py.svn-base b/eventlet/.svn/text-base/runloop_test.py.svn-base deleted file mode 100644 index 4827c32..0000000 --- a/eventlet/.svn/text-base/runloop_test.py.svn-base +++ /dev/null @@ -1,157 +0,0 @@ -"""\ -@file runloop_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 -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 time -import StringIO -import unittest - -from eventlet import runloop - - -class TestRunloop(unittest.TestCase): - mode = 'static' - def test_empty(self): - r = runloop.RunLoop() - r.schedule_call(0, r.abort) - r.run() - assert not r.running - - - def test_timer(self): - r = runloop.RunLoop() - r.schedule_call(0.125, r.abort) - start_time = time.time() - r.run() - assert time.time() - start_time >= 0.125 - assert not r.running - - def test_observer(self): - observed = [] - r = runloop.RunLoop() - r.add_observer(lambda runloop, activity: observed.append(activity)) - r.schedule_call(0, r.abort) - r.run() - assert observed == ['entry', 'before_timers', 'before_waiting', 'after_waiting', 'exit'] - assert not r.running - - - def test_remove_observer(self): - r = runloop.RunLoop() - - observed = [] - def observe(runloop, mode): - observed.append(mode) - r.remove_observer(observe) - - looped = [] - def run_loop_twice(runloop, mode): - if looped: - r.abort() - else: - looped.append(True) - - r.add_observer(observe, 'before_timers') - r.add_observer(run_loop_twice, 'after_waiting') - r.run() - assert len(observed) == 1 - assert not r.running - - def test_observer_exception(self): - r = runloop.RunLoop() - - observed = [] - def observe(runloop, mode): - observed.append(mode) - raise Exception("Squelch me please") - - looped = [] - def run_loop_twice(runloop, mode): - if looped: - r.abort() - else: - looped.append(True) - - saved = sys.stderr - sys.stderr = err = StringIO.StringIO() - - r.add_observer(observe, 'before_timers') - r.add_observer(run_loop_twice, 'after_waiting') - r.run() - - err.seek(0) - sys.stderr = saved - - assert len(observed) == 1 - assert err.read() - assert not r.running - - def test_timer_exception(self): - r = runloop.RunLoop() - - observed = [] - def timer(): - observed.append(True) - raise Exception("Squelch me please") - - looped = [] - def run_loop_twice(runloop, mode): - if looped: - r.abort() - else: - looped.append(True) - - saved = sys.stderr - sys.stderr = err = StringIO.StringIO() - - r.schedule_call(0, timer) - r.add_observer(run_loop_twice, 'after_waiting') - r.run() - - err.seek(0) - sys.stderr = saved - - assert len(observed) == 1 - assert err.read() - assert not r.running - - def test_timer_system_exception(self): - r = runloop.RunLoop() - def timer(): - raise SystemExit - - r.schedule_call(0, timer) - - caught = [] - try: - r.run() - except SystemExit: - caught.append(True) - - assert caught - assert not r.running - -if __name__ == '__main__': - unittest.main() - diff --git a/eventlet/.svn/text-base/saranwrap.py.svn-base b/eventlet/.svn/text-base/saranwrap.py.svn-base deleted file mode 100644 index 43e5fe3..0000000 --- a/eventlet/.svn/text-base/saranwrap.py.svn-base +++ /dev/null @@ -1,685 +0,0 @@ -"""\ -@file saranwrap.py -@author Phoenix -@date 2007-07-13 -@brief A simple, pickle based rpc mechanism which reflects python -objects and 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 -remote procedure calls. This is achieved by intercepting the basic -getattr and setattr calls in a client proxy, which commnicates those -down to the server which will dispatch them to objects in it's process -space. - -The basic protocol to get and set attributes is for the client proxy -to issue the command: - -getattr $id $name -setattr $id $name $value - -getitem $id $item -setitem $id $item $value -eq $id $rhs -del $id - -When the get returns a callable, the client proxy will provide a -callable proxy which will invoke a remote procedure call. The command -issued from the callable proxy to server is: - -call $id $name $args $kwargs - -If the client supplies an id of None, then the get/set/call is applied -to the object(s) exported from the server. - -The server will parse the get/set/call, take the action indicated, and -return back to the caller one of: - -value $val -callable -object $id -exception $excp - -To handle object expiration, the proxy will instruct the rpc server to -discard objects which are no longer in use. This is handled by -catching proxy deletion and sending the command: - -del $id - -The server will handle this by removing clearing it's own internal -references. This does not mean that the object will necessarily be -cleaned from the server, but no artificial references will remain -after successfully completing. On completion, the server will return -one of: - -value None -exception $excp - -The server also accepts a special command for debugging purposes: - -status - -Which will be intercepted by the server to write back: - -status {...} - -The wire protocol is to pickle the Request class in this file. The -request class is basically an action and a map of parameters' -""" - -import os -from cPickle import dumps, loads -import struct -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 import api, pools - -# debugging hooks -_g_debug_mode = False -if _g_debug_mode: - import traceback - import tempfile - -def pythonpath_sync(): - """ -@brief apply the current sys.path to the environment variable PYTHONPATH, so that child processes have the same paths as the caller does. -""" - pypath = os.pathsep.join(sys.path) - os.environ['PYTHONPATH'] = pypath - -def wrap(obj, dead_callback = None): - """ -@brief wrap in object in another process through a saranwrap proxy -@param object The object to wrap. -@param dead_callback A callable to invoke if the process exits.""" - - if type(obj).__name__ == 'module': - return wrap_module(obj.__name__, dead_callback) - pythonpath_sync() - if _g_debug_mode: - p = Process('python', [__file__, '--child', '--logfile', os.path.join(tempfile.gettempdir(), 'saranwrap.log')], dead_callback) - else: - p = Process('python', [__file__, '--child'], dead_callback) - prox = Proxy(ChildProcess(p, p)) - prox.obj = obj - return prox.obj - -def wrap_module(fqname, dead_callback = None): - """ -@brief wrap a module in another process through a saranwrap proxy -@param fqname The fully qualified name of the module. -@param dead_callback A callable to invoke if the process exits.""" - pythonpath_sync() - global _g_debug_mode - if _g_debug_mode: - p = Process('python', [__file__, '--module', fqname, '--logfile', os.path.join(tempfile.gettempdir(), 'saranwrap.log')], dead_callback) - else: - p = Process('python', [__file__, '--module', fqname,], dead_callback) - prox = Proxy(ChildProcess(p,p)) - return prox - -def status(proxy): - """ -@brief get the status from the server through a proxy -@param proxy a saranwrap.Proxy object connected to a server.""" - return proxy.__local_dict['_cp'].make_request(Request('status', {})) - -class BadResponse(Exception): - """"This exception is raised by an saranwrap client when it could - parse but cannot understand the response from the server.""" - pass - -class BadRequest(Exception): - """"This exception is raised by a saranwrap server when it could parse - but cannot understand the response from the server.""" - pass - -class UnrecoverableError(Exception): - pass - -class Request(object): - "@brief A wrapper class for proxy requests to the server." - def __init__(self, action, param): - self._action = action - self._param = param - def __str__(self): - return "Request `"+self._action+"` "+str(self._param) - def __getitem__(self, name): - return self._param[name] - def get(self, name, default = None): - try: - return self[name] - except KeyError: - return default - def action(self): - return self._action - -def _read_lp_hunk(stream): - len_bytes = stream.read(4) - length = struct.unpack('I', len_bytes)[0] - body = stream.read(length) - return body - -def _read_response(id, attribute, input, cp): - """@brief local helper method to read respones from the rpc server.""" - try: - str = _read_lp_hunk(input) - _prnt(`str`) - response = loads(str) - except (AttributeError, DeadProcess), e: - raise UnrecoverableError(e) - _prnt("response: %s" % response) - if response[0] == 'value': - return response[1] - elif response[0] == 'callable': - return CallableProxy(id, attribute, cp) - elif response[0] == 'object': - return ObjectProxy(cp, response[1]) - elif response[0] == 'exception': - exp = response[1] - raise exp - else: - raise BadResponse(response[0]) - -def _write_lp_hunk(stream, hunk): - write_length = struct.pack('I', len(hunk)) - stream.write(write_length + hunk) - if hasattr(stream, 'flush'): - stream.flush() - -def _write_request(param, output): - _prnt("request: %s" % param) - str = dumps(param) - _write_lp_hunk(output, str) - -def _is_local(attribute): - "Return true if the attribute should be handled locally" -# return attribute in ('_in', '_out', '_id', '__getattribute__', '__setattr__', '__dict__') - # good enough for now. :) - if '__local_dict' in attribute: - return True - return False - -def _prnt(message): - global _g_debug_mode - if _g_debug_mode: - print message - -_g_logfile = None -def _log(message): - global _g_logfile - if _g_logfile: - _g_logfile.write(str(os.getpid()) + ' ' + message) - _g_logfile.write('\n') - _g_logfile.flush() - -def _unmunge_attr_name(name): - """ Sometimes attribute names come in with classname prepended, not sure why. - This function removes said classname, because we're huge hackers and we didn't - find out what the true right thing to do is. *TODO: find out. """ - if(name.startswith('_Proxy')): - name = name[len('_Proxy'):] - if(name.startswith('_ObjectProxy')): - name = name[len('_ObjectProxy'):] - return name - -class ChildProcess(object): - """\ - This class wraps a remote python process, presumably available - in an instance of an Server. - """ - def __init__(self, instr, outstr, dead_list = None): - """ - @param instr a file-like object which supports read(). - @param outstr a file-like object which supports write() and flush(). - @param dead_list a list of ids of remote objects that are dead - """ - # default dead_list inside the function because all objects in method - # argument lists are init-ed only once globally - _prnt("ChildProcess::__init__") - if dead_list is None: - dead_list = set() - self._dead_list = dead_list - self._in = instr - self._out = outstr - self._lock = pools.TokenPool(max_size=1) - - def make_request(self, request, attribute=None): - _id = request.get('id') - - t = self._lock.get() - try: - _write_request(request, self._out) - retval = _read_response(_id, attribute, self._in, self) - finally: - self._lock.put(t) - - return retval - - -class Proxy(object): - """\ -@class Proxy -@brief This is the class you will typically use as a client to a child -process. - -Simply instantiate one around a file-like interface and start -calling methods on the thing that is exported. The dir() builtin is -not supported, so you have to know what has been exported. -""" - def __init__(self, cp): - """@param A ChildProcess instance that wraps the i/o to the child process. - """ - #_prnt("Proxy::__init__") - self.__local_dict = dict( - _cp = cp, - _id = None) - - def __getattribute__(self, attribute): - #_prnt("Proxy::__getattr__: %s" % attribute) - if _is_local(attribute): - # call base class getattribute so we actually get the local variable - attribute = _unmunge_attr_name(attribute) - return super(Proxy, self).__getattribute__(attribute) - elif attribute in ('__deepcopy__', '__copy__'): - # redirect copy function calls to our own versions instead of - # to the proxied object - return super(Proxy, self).__getattribute__('__deepcopy__') - else: - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - - _dead_list = my_cp._dead_list - for dead_object in _dead_list.copy(): - request = Request('del', {'id':dead_object}) - - my_cp.make_request(request) - _dead_list.remove(dead_object) - - # Pass all public attributes across to find out if it is - # callable or a simple attribute. - request = Request('getattr', {'id':my_id, 'attribute':attribute}) - return my_cp.make_request(request, attribute=attribute) - - def __setattr__(self, attribute, value): - #_prnt("Proxy::__setattr__: %s" % attribute) - if _is_local(attribute): - # It must be local to this actual object, so we have to apply - # it to the dict in a roundabout way - attribute = _unmunge_attr_name(attribute) - super(Proxy, self).__getattribute__('__dict__')[attribute]=value - else: - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - # Pass the set attribute across - request = Request('setattr', {'id':my_id, 'attribute':attribute, 'value':value}) - return my_cp.make_request(request, attribute=attribute) - -class ObjectProxy(Proxy): - """\ -@class ObjectProxy -@brief This class wraps a remote object in the Server - -This class will be created during normal operation, and users should -not need to deal with this class directly.""" - - def __init__(self, cp, _id): - """\ -@param cp A ChildProcess object that wraps the i/o of a child process. -@param _id an identifier for the remote object. humans do not provide this. -""" - Proxy.__init__(self, cp) - self.__local_dict['_id'] = _id - #_prnt("ObjectProxy::__init__ %s" % _id) - - def __del__(self): - my_id = self.__local_dict['_id'] - #_prnt("ObjectProxy::__del__ %s" % my_id) - self.__local_dict['_cp']._dead_list.add(my_id) - - def __getitem__(self, key): - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - request = Request('getitem', {'id':my_id, 'key':key}) - return my_cp.make_request(request, attribute=key) - - def __setitem__(self, key, value): - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - request = Request('setitem', {'id':my_id, 'key':key, 'value':value}) - return my_cp.make_request(request, attribute=key) - - def __eq__(self, rhs): - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - request = Request('eq', {'id':my_id, 'rhs':rhs.__local_dict['_id']}) - return my_cp.make_request(request) - - def __repr__(self): - # apparently repr(obj) skips the whole getattribute thing and just calls __repr__ - # directly. Therefore we just pass it through the normal call pipeline, and - # tack on a little header so that you can tell it's an object proxy. - val = self.__repr__() - return "saran:%s" % val - - def __str__(self): - # see description for __repr__, because str(obj) works the same. We don't - # tack anything on to the return value here because str values are used as data. - return self.__str__() - - def __nonzero__(self): - # bool(obj) is another method that skips __getattribute__. There's no good way to just pass - # the method on, so we use a special message. - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - request = Request('nonzero', {'id':my_id}) - return my_cp.make_request(request) - - def __len__(self): - # see description for __repr__, len(obj) is the same. - return self.__len__() - - def __deepcopy__(self, memo=None): - """Copies the entire external object and returns its - value. Will only work if the remote object is pickleable.""" - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - request = Request('copy', {'id':my_id}) - return my_cp.make_request(request) - - # since the remote object is being serialized whole anyway, - # there's no semantic difference between copy and deepcopy - __copy__ = __deepcopy__ - - -def proxied_type(self): - if type(self) is not ObjectProxy: - return type(self) - - my_cp = self.__local_dict['_cp'] - my_id = self.__local_dict['_id'] - request = Request('type', {'id':my_id}) - return my_cp.make_request(request) - -class CallableProxy(object): - """\ -@class CallableProxy -@brief This class wraps a remote function in the Server - -This class will be created by an Proxy during normal operation, -and users should not need to deal with this class directly.""" - - def __init__(self, object_id, name, cp): - #_prnt("CallableProxy::__init__: %s, %s" % (object_id, name)) - self._object_id = object_id - self._name = name - self._cp = cp - - def __call__(self, *args, **kwargs): - #_prnt("CallableProxy::__call__: %s, %s" % (args, kwargs)) - - # Pass the call across. We never build a callable without - # having already checked if the method starts with '_' so we - # can safely pass this one to the remote object. - #_prnt("calling %s %s" % (self._object_id, self._name) - request = Request('call', {'id':self._object_id, 'name':self._name, 'args':args, 'kwargs':kwargs}) - return self._cp.make_request(request, attribute=self._name) - -class Server(object): - def __init__(self, input, output, export): - """\ -@param input a file-like object which supports read(). -@param output a file-like object which supports write() and flush(). -@param export an object, function, or map which is exported to clients -when the id is None.""" - #_log("Server::__init__") - self._in = input - self._out = output - self._export = export - self._next_id = 1 - self._objects = {} - - def handle_status(self, obj, req): - return { - 'object_count':len(self._objects), - 'next_id':self._next_id, - 'pid':os.getpid()} - - def handle_getattr(self, obj, req): - try: - return getattr(obj, req['attribute']) - except AttributeError, e: - if hasattr(obj, "__getitem__"): - return obj[req['attribute']] - else: - raise e - #_log('getattr: %s' % str(response)) - - def handle_setattr(self, obj, req): - try: - return setattr(obj, req['attribute'], req['value']) - except AttributeError, e: - if hasattr(obj, "__setitem__"): - return obj.__setitem__(req['attribute'], req['value']) - else: - raise e - - def handle_getitem(self, obj, req): - return obj[req['key']] - - def handle_setitem(self, obj, req): - obj[req['key']] = req['value'] - return None # *TODO figure out what the actual return value of __setitem__ should be - - def handle_eq(self, obj, req): - #_log("__eq__ %s %s" % (obj, req)) - rhs = None - try: - rhs = self._objects[req['rhs']] - except KeyError, e: - return False - return (obj == rhs) - - def handle_call(self, obj, req): - #_log("calling %s " % (req['name'])) - try: - fn = getattr(obj, req['name']) - except AttributeError, e: - if hasattr(obj, "__setitem__"): - fn = obj[req['name']] - else: - raise e - - return fn(*req['args'],**req['kwargs']) - - def handle_del(self, obj, req): - id = req['id'] - _log("del %s from %s" % (id, self._objects)) - - # *TODO what does __del__ actually return? - del self._objects[id] - return None - - def handle_type(self, obj, req): - return type(obj) - - def handle_nonzero(self, obj, req): - return bool(obj) - - def handle_copy(self, obj, req): - return obj - - def loop(self): - """@brief Loop forever and respond to all requests.""" - _log("Server::loop") - while True: - try: - try: - str = _read_lp_hunk(self._in) - except EOFError: - sys.exit(0) # normal exit - request = loads(str) - _log("request: %s (%s)" % (request, self._objects)) - req = request - id = None - obj = None - try: - id = req['id'] - if id: - id = int(id) - obj = self._objects[id] - #_log("id, object: %d %s" % (id, obj)) - except Exception, e: - #_log("Exception %s" % str(e)) - pass - if obj is None or id is None: - id = None - obj = self._export - #_log("found object %s" % str(obj)) - - # Handle the request via a method with a special name on the server - handler_name = 'handle_%s' % request.action() - - try: - handler = getattr(self, handler_name) - except AttributeError: - raise BadRequest, request.action() - - response = handler(obj, request) - - # figure out what to do with the response, and respond - # apprpriately. - if request.action() in ['status', 'type', 'copy']: - # have to handle these specially since we want to - # pickle up the actual value and not return a proxy - self.respond(['value', response]) - elif callable(response): - #_log("callable %s" % response) - self.respond(['callable']) - elif self.is_value(response): - self.respond(['value', response]) - else: - self._objects[self._next_id] = response - #_log("objects: %s" % str(self._objects)) - self.respond(['object', self._next_id]) - self._next_id += 1 - except SystemExit, e: - raise e - except Exception, e: - self.write_exception(e) - except: - self.write_exception(sys.exc_info()[0]) - - def is_value(self, value): - """\ -@brief Test if value should be serialized as a simple dataset. -@param value The value to test. -@return Returns true if value is a simple serializeable set of data. -""" - return type(value) in (str,unicode,int,float,long,bool,type(None)) - - def respond(self, body): - _log("responding with: %s" % body) - #_log("objects: %s" % self._objects) - s = dumps(body) - _log(`s`) - str = _write_lp_hunk(self._out, s) - - def write_exception(self, e): - """@brief Helper method to respond with an exception.""" - #_log("exception: %s" % sys.exc_info()[0]) - # TODO: serialize traceback using generalization of code from mulib.htmlexception - self.respond(['exception', e]) - global _g_debug_mode - if _g_debug_mode: - _log("traceback: %s" % traceback.format_tb(sys.exc_info()[2])) - - -# test function used for testing that final except clause -def raise_a_weird_error(): - raise "oh noes you can raise a string" - -# test function used for testing return of unpicklable exceptions -def raise_an_unpicklable_error(): - class Unpicklable(Exception): - pass - raise Unpicklable() - -# test function used for testing return of picklable exceptions -def raise_standard_error(): - raise FloatingPointError() - -# test function to make sure print doesn't break the wrapper -def print_string(str): - print str - -# test function to make sure printing on stdout doesn't break the -# wrapper -def err_string(str): - print >>sys.stderr, str - -def main(): - import optparse - parser = optparse.OptionParser( - usage="usage: %prog [options]", - description="Simple saranwrap.Server wrapper") - parser.add_option( - '-c', '--child', default=False, action='store_true', - help='Wrap an object serialized via setattr.') - parser.add_option( - '-m', '--module', type='string', dest='module', default=None, - help='a module to load and export.') - parser.add_option( - '-l', '--logfile', type='string', dest='logfile', default=None, - help='file to log to.') - options, args = parser.parse_args() - global _g_logfile - if options.logfile: - _g_logfile = open(options.logfile, 'a') - if options.module: - export = api.named(options.module) - server = Server(sys.stdin, sys.stdout, export) - elif options.child: - server = Server(sys.stdin, sys.stdout, {}) - - # *HACK: some modules may emit on stderr, which breaks everything. - class NullSTDOut(object): - def write(a, b): - pass - sys.stderr = NullSTDOut() - sys.stdout = NullSTDOut() - - # Loop until EOF - server.loop() - if _g_logfile: - _g_logfile.close() - - -if __name__ == "__main__": - main() diff --git a/eventlet/.svn/text-base/saranwrap_test.py.svn-base b/eventlet/.svn/text-base/saranwrap_test.py.svn-base deleted file mode 100644 index df0878d..0000000 --- a/eventlet/.svn/text-base/saranwrap_test.py.svn-base +++ /dev/null @@ -1,316 +0,0 @@ -#!/usr/bin/python -# @file test_saranwrap.py -# @brief Test cases for saranwrap. -# -# 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 import saranwrap, coros - -import os -import sys -import tempfile -import time -import unittest -import uuid - -# random test stuff -def list_maker(): - return [0,1,2] - -one = 1 -two = 2 -three = 3 - -class TestSaranwrap(unittest.TestCase): - def assert_server_exists(self, prox): - self.assert_(saranwrap.status(prox)) - prox.foo = 0 - self.assertEqual(0, prox.foo) - - def test_wrap_tuple(self): - my_tuple = (1, 2) - prox = saranwrap.wrap(my_tuple) - self.assertEqual(prox[0], 1) - self.assertEqual(prox[1], 2) - self.assertEqual(len(my_tuple), 2) - - def test_wrap_string(self): - my_object = "whatever" - prox = saranwrap.wrap(my_object) - self.assertEqual(str(my_object), str(prox)) - self.assertEqual(len(my_object), len(prox)) - self.assertEqual(my_object.join(['a', 'b']), prox.join(['a', 'b'])) - - def test_wrap_uniterable(self): - # here we're treating the exception as just a normal class - prox = saranwrap.wrap(FloatingPointError()) - def index(): - prox[0] - def key(): - prox['a'] - - self.assertRaises(IndexError, index) - self.assertRaises(TypeError, key) - - def test_wrap_dict(self): - my_object = {'a':1} - prox = saranwrap.wrap(my_object) - self.assertEqual('a', prox.keys()[0]) - self.assertEqual(1, prox['a']) - self.assertEqual(str(my_object), str(prox)) - self.assertEqual('saran:' + repr(my_object), repr(prox)) - self.assertEqual('saran:' + `my_object`, `prox`) - - def test_wrap_module_class(self): - prox = saranwrap.wrap(uuid) - self.assertEqual(saranwrap.Proxy, type(prox)) - id = prox.uuid4() - self.assertEqual(id.get_version(), uuid.uuid4().get_version()) - self.assert_(repr(prox.uuid4)) - - def test_wrap_eq(self): - prox = saranwrap.wrap(uuid) - id1 = prox.uuid4() - id2 = prox.UUID(str(id1)) - self.assertEqual(id1, id2) - id3 = prox.uuid4() - self.assert_(id1 != id3) - - def test_wrap_nonzero(self): - prox = saranwrap.wrap(uuid) - id1 = prox.uuid4() - self.assert_(bool(id1)) - prox2 = saranwrap.wrap([1, 2, 3]) - self.assert_(bool(prox2)) - - def test_multiple_wraps(self): - prox1 = saranwrap.wrap(uuid) - prox2 = saranwrap.wrap(uuid) - x1 = prox1.uuid4() - x2 = prox1.uuid4() - del x2 - x3 = prox2.uuid4() - - def test_dict_passthru(self): - prox = saranwrap.wrap(uuid) - x = prox.uuid4() - self.assertEqual(type(x.__dict__), saranwrap.ObjectProxy) - # try it all on one line just for the sake of it - self.assertEqual(type(saranwrap.wrap(uuid).uuid4().__dict__), saranwrap.ObjectProxy) - - def test_is_value(self): - server = saranwrap.Server(None, None, None) - self.assert_(server.is_value(None)) - - def test_wrap_getitem(self): - prox = saranwrap.wrap([0,1,2]) - self.assertEqual(prox[0], 0) - - def test_wrap_setitem(self): - prox = saranwrap.wrap([0,1,2]) - prox[1] = 2 - self.assertEqual(prox[1], 2) - - def test_raising_exceptions(self): - prox = saranwrap.wrap(uuid) - def nofunc(): - prox.never_name_a_function_like_this() - self.assertRaises(AttributeError, nofunc) - - def test_raising_weird_exceptions(self): - # the recursion is killing me! - prox = saranwrap.wrap(saranwrap) - try: - prox.raise_a_weird_error() - self.assert_(False) - except: - import sys - ex = sys.exc_info()[0] - self.assertEqual(ex, "oh noes you can raise a string") - self.assert_server_exists(prox) - - def test_unpicklable_server_exception(self): - prox = saranwrap.wrap(saranwrap) - def unpickle(): - prox.raise_an_unpicklable_error() - - self.assertRaises(saranwrap.UnrecoverableError, unpickle) - - # It's basically dead - #self.assert_server_exists(prox) - - def test_pickleable_server_exception(self): - prox = saranwrap.wrap(saranwrap) - def fperror(): - prox.raise_standard_error() - - self.assertRaises(FloatingPointError, fperror) - self.assert_server_exists(prox) - - def test_print_does_not_break_wrapper(self): - prox = saranwrap.wrap(saranwrap) - prox.print_string('hello') - self.assert_server_exists(prox) - - def test_stderr_does_not_break_wrapper(self): - prox = saranwrap.wrap(saranwrap) - prox.err_string('goodbye') - self.assert_server_exists(prox) - - def assertLessThan(self, a, b): - self.assert_(a < b, "%s is not less than %s" % (a, b)) - - def test_status(self): - prox = saranwrap.wrap(time) - a = prox.gmtime(0) - status = saranwrap.status(prox) - self.assertEqual(status['object_count'], 1) - self.assertEqual(status['next_id'], 2) - self.assert_(status['pid']) # can't guess what it will be - # status of an object should be the same as the module - self.assertEqual(saranwrap.status(a), status) - # create a new one then immediately delete it - prox.gmtime(1) - is_id = prox.ctime(1) # sync up deletes - status = saranwrap.status(prox) - self.assertEqual(status['object_count'], 1) - self.assertEqual(status['next_id'], 3) - prox2 = saranwrap.wrap(uuid) - self.assert_(status['pid'] != saranwrap.status(prox2)['pid']) - - def test_del(self): - prox = saranwrap.wrap(time) - delme = prox.gmtime(0) - status_before = saranwrap.status(prox) - #print status_before['objects'] - del delme - # need to do an access that doesn't create an object - # in order to sync up the deleted objects - prox.ctime(1) - status_after = saranwrap.status(prox) - #print status_after['objects'] - self.assertLessThan(status_after['object_count'], status_before['object_count']) - - def test_variable_and_keyword_arguments_with_function_calls(self): - import optparse - prox = saranwrap.wrap(optparse) - parser = prox.OptionParser() - z = parser.add_option('-n', action='store', type='string', dest='n') - opts,args = parser.parse_args(["-nfoo"]) - self.assertEqual(opts.n, 'foo') - - def test_original_proxy_going_out_of_scope(self): - def make_uuid(): - prox = saranwrap.wrap(uuid) - # after this function returns, prox should fall out of scope - return prox.uuid4() - tid = make_uuid() - self.assertEqual(tid.get_version(), uuid.uuid4().get_version()) - def make_list(): - from eventlet import saranwrap_test - prox = saranwrap.wrap(saranwrap_test.list_maker) - # after this function returns, prox should fall out of scope - return prox() - proxl = make_list() - self.assertEqual(proxl[2], 2) - - def test_status_of_none(self): - try: - saranwrap.status(None) - self.assert_(False) - except AttributeError, e: - pass - - def test_not_inheriting_pythonpath(self): - # construct a fake module in the temp directory - temp_dir = tempfile.mkdtemp("saranwrap_test") - fp = open(os.path.join(temp_dir, "jitar_hero.py"), "w") - fp.write("""import os, sys -pypath = os.environ['PYTHONPATH'] -sys_path = sys.path""") - fp.close() - - # this should fail because we haven't stuck the temp_dir in our path yet - prox = saranwrap.wrap_module('jitar_hero') - import cPickle - try: - prox.pypath - self.fail() - except cPickle.UnpicklingError: - pass - - # now try to saranwrap it - sys.path.append(temp_dir) - try: - import jitar_hero - prox = saranwrap.wrap(jitar_hero) - self.assert_(prox.pypath.count(temp_dir)) - self.assert_(prox.sys_path.count(temp_dir)) - finally: - import shutil - shutil.rmtree(temp_dir) - sys.path.remove(temp_dir) - - def test_contention(self): - from eventlet import saranwrap_test - prox = saranwrap.wrap(saranwrap_test) - - pool = coros.CoroutinePool(max_size=4) - waiters = [] - waiters.append(pool.execute(lambda: self.assertEquals(prox.one, 1))) - waiters.append(pool.execute(lambda: self.assertEquals(prox.two, 2))) - waiters.append(pool.execute(lambda: self.assertEquals(prox.three, 3))) - for waiter in waiters: - waiter.wait() - - def test_copy(self): - import copy - compound_object = {'a':[1,2,3]} - prox = saranwrap.wrap(compound_object) - def make_assertions(copied): - self.assert_(isinstance(copied, dict)) - self.assert_(isinstance(copied['a'], list)) - self.assertEquals(copied, compound_object) - self.assertNotEqual(id(compound_object), id(copied)) - - make_assertions(copy.copy(prox)) - make_assertions(copy.deepcopy(prox)) - - def test_list_of_functions(self): - return # this test is known to fail, we can implement it sometime in the future if we wish - from eventlet import saranwrap_test - prox = saranwrap.wrap([saranwrap_test.list_maker]) - self.assertEquals(list_maker(), prox[0]()) - - def test_detection_of_server_crash(self): - # make the server crash here - pass - - def test_equality_with_local_object(self): - # we'll implement this if there's a use case for it - pass - - def test_non_blocking(self): - # here we test whether it's nonblocking - pass - -if __name__ == '__main__': - unittest.main() diff --git a/eventlet/.svn/text-base/selecthub.py.svn-base b/eventlet/.svn/text-base/selecthub.py.svn-base deleted file mode 100644 index 60e2bb6..0000000 --- a/eventlet/.svn/text-base/selecthub.py.svn-base +++ /dev/null @@ -1,173 +0,0 @@ -"""\ -@file selecthub.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. -""" - -import sys -import select -import errno -import traceback -import time -from bisect import insort, bisect_left - -from eventlet import greenlib -from eventlet.runloop import RunLoop, Timer - -import greenlet - -class Hub(object): - def __init__(self): - self.runloop = RunLoop(self.wait) - self.readers = {} - self.writers = {} - self.excs = {} - self.descriptors = {} - self.descriptor_queue = {} - self.greenlet = None - - def stop(self): - self.process_queue() - self.runloop.abort() - if self.greenlet is not greenlet.getcurrent(): - self.switch() - - def schedule_call(self, *args, **kw): - return self.runloop.schedule_call(*args, **kw) - - def switch(self): - if not self.greenlet: - self.greenlet = greenlib.tracked_greenlet() - args = ((self.runloop.run,),) - else: - args = () - try: - greenlet.getcurrent().parent = self.greenlet - except ValueError: - pass - return greenlib.switch(self.greenlet, *args) - - def add_descriptor(self, fileno, read=None, write=None, exc=None): - self.descriptor_queue[fileno] = read, write, exc - - def remove_descriptor(self, fileno): - self.descriptor_queue[fileno] = None, None, None - - def exc_descriptor(self, fileno): - # We must handle two cases here, the descriptor - # may be changing or removing its exc handler - # in the queue, or it may be waiting on the queue. - exc = None - try: - exc = self.descriptor_queue[fileno][2] - except KeyError: - try: - exc = self.excs[fileno] - except KeyError: - pass - if exc is not None: - try: - exc(fileno) - except self.runloop.SYSTEM_EXCEPTIONS: - self.squelch_exception(fileno, sys.exc_info()) - - def squelch_exception(self, fileno, exc_info): - traceback.print_exception(*exc_info) - print >>sys.stderr, "Removing descriptor: %r" % (fileno,) - try: - self.remove_descriptor(fileno) - except Exception, e: - print >>sys.stderr, "Exception while removing descriptor! %r" % (e,) - - def process_queue(self): - readers = self.readers - writers = self.writers - excs = self.excs - descriptors = self.descriptors - for fileno, rwe in self.descriptor_queue.iteritems(): - read, write, exc = rwe - if read is None and write is None and exc is None: - try: - del descriptors[fileno] - except KeyError: - continue - try: - del readers[fileno] - except KeyError: - pass - try: - del writers[fileno] - except KeyError: - pass - try: - del excs[fileno] - except KeyError: - pass - else: - if read is not None: - readers[fileno] = read - else: - try: - del readers[fileno] - except KeyError: - pass - if write is not None: - writers[fileno] = write - else: - try: - del writers[fileno] - except KeyError: - pass - if exc is not None: - excs[fileno] = exc - else: - try: - del excs[fileno] - except KeyError: - pass - descriptors[fileno] = rwe - self.descriptor_queue.clear() - - def wait(self, seconds=None): - self.process_queue() - if not self.descriptors: - if seconds: - time.sleep(seconds) - return - readers = self.readers - writers = self.writers - excs = self.excs - try: - r, w, ig = select.select(readers.keys(), writers.keys(), [], seconds) - except select.error, e: - if e.args[0] == errno.EINTR: - return - raise - SYSTEM_EXCEPTIONS = self.runloop.SYSTEM_EXCEPTIONS - for observed, events in ((readers, r), (writers, w)): - for fileno in events: - try: - observed[fileno](fileno) - except SYSTEM_EXCEPTIONS: - raise - except: - self.squelch_exception(fileno, sys.exc_info()) diff --git a/eventlet/.svn/text-base/stacklesssupport.py.svn-base b/eventlet/.svn/text-base/stacklesssupport.py.svn-base deleted file mode 100644 index 8e97555..0000000 --- a/eventlet/.svn/text-base/stacklesssupport.py.svn-base +++ /dev/null @@ -1,110 +0,0 @@ -"""\ -@file __init__.py -@brief Support for using stackless python. Broken and riddled with -print statements at the moment. Please fix it! - -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 types - -import stackless -import traceback - - -caller = None - - -coro_args = {} - - -tasklet_to_greenlet = {} - - -def getcurrent(): - return tasklet_to_greenlet[stackless.getcurrent()] - - -class FirstSwitch(object): - def __init__(self, gr): - self.gr = gr - - def __call__(self, *args, **kw): - print "first call", args, kw - gr = self.gr - del gr.switch - run, gr.run = gr.run, None - t = stackless.tasklet(run) - gr.t = t - tasklet_to_greenlet[t] = gr - t.setup(*args, **kw) - result = t.run() - - -class greenlet(object): - def __init__(self, run=None, parent=None): - self.dead = False - if parent is None: - parent = getcurrent() - - self.parent = parent - if run is not None: - self.run = run - - self.switch = FirstSwitch(self) - - def switch(self, *args): - print "switch", args - global caller - caller = stackless.getcurrent() - coro_args[self] = args - self.t.insert() - stackless.schedule() - if caller is not self.t: - caller.remove() - rval = coro_args[self] - return rval - - def run(self): - pass - - def __bool__(self): - return self.run is None and not self.dead - - -class GreenletExit(Exception): - pass - - -def emulate(): - module = types.ModuleType('greenlet') - sys.modules['greenlet'] = module - module.greenlet = greenlet - module.getcurrent = getcurrent - module.GreenletExit = GreenletExit - - caller = t = stackless.getcurrent() - tasklet_to_greenlet[t] = None - main_coro = greenlet() - tasklet_to_greenlet[t] = main_coro - main_coro.t = t - del main_coro.switch ## It's already running - coro_args[main_coro] = None diff --git a/eventlet/.svn/text-base/tests.py.svn-base b/eventlet/.svn/text-base/tests.py.svn-base deleted file mode 100644 index 41968c2..0000000 --- a/eventlet/.svn/text-base/tests.py.svn-base +++ /dev/null @@ -1,89 +0,0 @@ -"""\ -@file tests.py -@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 -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 errno -import os -import sys -import unittest, doctest - - -TestCase = unittest.TestCase - - -name = getattr(sys.modules['__main__'], '__name__', None) -main = unittest.main - -# listing of files containing doctests -doc_test_files = ['coros'] - -def find_command(command): - for dir in os.getenv('PATH', '/usr/bin:/usr/sbin').split(os.pathsep): - p = os.path.join(dir, command) - if os.access(p, os.X_OK): - return p - raise IOError(errno.ENOENT, 'Command not found: %r' % command) - -def run_all_tests(test_files = doc_test_files): - """ Runs all the unit tests, returning immediately after the - first failed test. - - Returns true if the tests all succeeded. This method is really much longer - than it ought to be. - """ - eventlet_dir = os.path.realpath(os.path.dirname(__file__)) - if eventlet_dir not in sys.path: - sys.path.append(eventlet_dir) - - # add all _test files as a policy - import glob - test_files += [os.path.splitext(os.path.basename(x))[0] - for x in glob.glob(os.path.join(eventlet_dir, "*_test.py"))] - test_files.sort() - - for test_file in test_files: - print "-=", test_file, "=-" - try: - test_module = __import__(test_file) - except ImportError: - print "Unable to import %s, skipping" % test_file - continue - - if test_file.endswith('_test'): - # gawd, unittest, why you make it so difficult to just run some tests! - suite = unittest.findTestCases(test_module) - result = unittest.TextTestRunner().run(suite) - if not result.wasSuccessful(): - return False - else: - failures, tests = doctest.testmod(test_module) - if failures: - return False - else: - print "OK" - - return True - -if __name__ == '__main__': - run_all_tests() diff --git a/eventlet/.svn/text-base/timer.py.svn-base b/eventlet/.svn/text-base/timer.py.svn-base deleted file mode 100644 index a91390a..0000000 --- a/eventlet/.svn/text-base/timer.py.svn-base +++ /dev/null @@ -1,83 +0,0 @@ -"""\ -@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. -""" -from eventlet.api import get_hub - -""" If true, captures a stack trace for each timer when constructed. This is -useful for debugging leaking timers, to find out where the timer was set up. """ -_g_debug = False - -class Timer(object): - __slots__ = ['seconds', 'tpl', 'called', 'cancelled', 'scheduled_time', 'greenlet', 'traceback'] - def __init__(self, seconds, cb, *args, **kw): - """Create a timer. - seconds: The minimum number of seconds to wait before calling - cb: The callback to call when the timer has expired - *args: The arguments to pass to cb - **kw: The keyword arguments to pass to cb - - This timer will not be run unless it is scheduled in a runloop by - calling timer.schedule() or runloop.add_timer(timer). - """ - self.cancelled = False - self.seconds = seconds - self.tpl = cb, args, kw - self.called = False - if _g_debug: - import traceback, cStringIO - self.traceback = cStringIO.StringIO() - traceback.print_stack(file=self.traceback) - - def __repr__(self): - secs = getattr(self, 'seconds', None) - cb, args, kw = getattr(self, 'tpl', (None, None, None)) - retval = "Timer(%s, %s, *%s, **%s)" % ( - secs, cb, args, kw) - if _g_debug and hasattr(self, 'traceback'): - retval += '\n' + self.traceback.getvalue() - return retval - - def copy(self): - cb, args, kw = self.tpl - return self.__class__(self.seconds, cb, *args, **kw) - - def schedule(self): - """Schedule this timer to run in the current runloop. - """ - self.called = False - self.scheduled_time = get_hub().runloop.add_timer(self) - return self - - def __call__(self): - if not self.called: - self.called = True - cb, args, kw = self.tpl - cb(*args, **kw) - - def cancel(self): - """Prevent this timer from being called. If the timer has already - been called, has no effect. - """ - self.cancelled = True - self.called = True diff --git a/eventlet/.svn/text-base/timer_test.py.svn-base b/eventlet/.svn/text-base/timer_test.py.svn-base deleted file mode 100644 index 496a884..0000000 --- a/eventlet/.svn/text-base/timer_test.py.svn-base +++ /dev/null @@ -1,66 +0,0 @@ -"""\ -@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 -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 unittest - -from eventlet import api, runloop, tests, timer - -class TestTimer(tests.TestCase): - mode = 'static' - def test_copy(self): - t = timer.Timer(0, lambda: None) - t2 = t.copy() - assert t.seconds == t2.seconds - assert t.tpl == t2.tpl - assert t.called == t2.called - - def test_cancel(self): - r = runloop.RunLoop() - called = [] - t = timer.Timer(0, lambda: called.append(True)) - t.cancel() - r.add_timer(t) - r.add_observer(lambda r, activity: r.abort(), 'after_waiting') - r.run() - assert not called - assert not r.running - - def test_schedule(self): - hub = api.get_hub() - r = hub.runloop - # clean up the runloop, preventing side effects from previous tests - # on this thread - if r.running: - r.abort() - api.sleep(0) - called = [] - t = timer.Timer(0, lambda: (called.append(True), hub.runloop.abort())) - t.schedule() - r.default_sleep = lambda: 0.0 - r.run() - assert called - assert not r.running - -if __name__ == '__main__': - unittest.main() diff --git a/eventlet/.svn/text-base/tls.py.svn-base b/eventlet/.svn/text-base/tls.py.svn-base deleted file mode 100644 index 3cb3921..0000000 --- a/eventlet/.svn/text-base/tls.py.svn-base +++ /dev/null @@ -1,57 +0,0 @@ -"""\ -@file tls.py -@author Donovan Preston - -Copyright (c) 2006-2007, Linden Research, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -""" - -import threading -import weakref - -__all__ = ['local'] - -class _local(object): - """ - Crappy Python 2.3 compatible implementation of thread-local storage - """ - - __slots__ = ('__thread_dict__',) - - def __init__(self): - object.__setattr__(self, '__thread_dict__', weakref.WeakKeyDictionary()) - - def __getattr__(self, attr): - try: - return self.__thread_dict__[threading.currentThread()][attr] - except KeyError: - raise AttributeError(attr) - - def __setattr__(self, attr, value): - t = threading.currentThread() - try: - d = self.__thread_dict__[t] - except KeyError: - d = self.__thread_dict__[t] = {} - d[attr] = value - -try: - local = threading.local -except AttributeError: - local = _local diff --git a/eventlet/.svn/text-base/tpool.py.svn-base b/eventlet/.svn/text-base/tpool.py.svn-base deleted file mode 100644 index 6ca505d..0000000 --- a/eventlet/.svn/text-base/tpool.py.svn-base +++ /dev/null @@ -1,123 +0,0 @@ -"""\ -@file tpool.py - -Copyright (c) 2007, Linden Research, Inc. -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 -import Queue - -from sys import stdout -from Queue import Empty, Queue - -from eventlet import api, coros, httpc, httpd, util, wrappedfd -from eventlet.api import trampoline, get_hub - -_rpipe, _wpipe = os.pipe() -_rfile = os.fdopen(_rpipe,"r",0) -_wrap_rfile = wrappedfd.wrapped_file(_rfile) -util.set_nonblocking(_rfile) - -def _signal_t2e(): - nwritten = os.write(_wpipe,' ') - -_reqq = Queue(maxsize=-1) -_rspq = Queue(maxsize=-1) - -def tpool_trampoline(): - global _reqq, _rspq - while(True): - _c = _wrap_rfile.recv(1) - assert(_c != "") - while not _rspq.empty(): - try: - (e,rv) = _rspq.get(block=False) - e.send(rv) - except Empty: - pass - -def esend(meth,*args, **kwargs): - global _reqq, _rspq - e = coros.event() - _reqq.put((e,meth,args,kwargs)) - return e - -def tworker(): - global _reqq, _rspq - while(True): - (e,meth,args,kwargs) = _reqq.get() - rv = None - try: - rv = meth(*args,**kwargs) - except Exception,exn: - import sys, traceback - (a,b,tb) = sys.exc_info() - rv = (exn,a,b,tb) - _rspq.put((e,rv)) - _signal_t2e() - -def erecv(e): - rv = e.wait() - if isinstance(rv,tuple) and len(rv) == 4 and isinstance(rv[0],Exception): - import sys, traceback - (e,a,b,tb) = rv - traceback.print_exception(Exception,e,tb) - traceback.print_stack() - raise e - return rv - -def erpc(meth,*args, **kwargs): - e = esend(meth,*args,**kwargs) - rv = erecv(e) - return rv - -class Proxy(object): - """ a simple proxy-wrapper of any object that comes with a methods-only interface, - in order to forward every method invocation onto a thread in the native-thread pool. - A key restriction is that the object's methods cannot call into eventlets, since the - eventlet dispatcher runs on a different native thread. This is for running native-threaded - code only. """ - def __init__(self, obj,autowrap=()): - self._obj = obj - self._autowrap = autowrap - - def __getattr__(self,attr_name): - f = getattr(self._obj,attr_name) - if not callable(f): - return f - def doit(*args, **kwargs): - if kwargs.pop('nonblocking',False): - rv = f(*args, **kwargs) - else: - rv = erpc(f,*args,**kwargs) - if type(rv) in self._autowrap: - return Proxy(rv) - else: - return rv - return doit - -_nthreads = 20 -_threads = {} -def setup(): - global _threads - for i in range(0,_nthreads): - _threads[i] = threading.Thread(target=tworker) - _threads[i].setDaemon(True) - _threads[i].start() - - api.spawn(tpool_trampoline) - -setup() diff --git a/eventlet/.svn/text-base/tpool_test.py.svn-base b/eventlet/.svn/text-base/tpool_test.py.svn-base deleted file mode 100644 index 19442bc..0000000 --- a/eventlet/.svn/text-base/tpool_test.py.svn-base +++ /dev/null @@ -1,70 +0,0 @@ -"""\ -@file tpool_test.py - -Copyright (c) 2007, Linden Research, Inc. -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, tests - -from eventlet.tpool import erpc -from sys import stdout - -import random -r = random.WichmannHill() - -_g_debug = False - -def prnt(msg): - if _g_debug: - print msg - -class yadda(object): - def __init__(self): - pass - - def foo(self,when,n=None): - assert(n is not None) - prnt("foo: %s, %s" % (when,n)) - time.sleep(r.random()) - return n - -def sender_loop(pfx): - n = 0 - obj = tpool.Proxy(yadda()) - while n < 10: - api.sleep(0) - now = time.time() - prnt("%s: send (%s,%s)" % (pfx,now,n)) - rv = obj.foo(now,n=n) - prnt("%s: recv %s" % (pfx, rv)) - assert(n == rv) - api.sleep(0) - n += 1 - - -class TestTpool(tests.TestCase): - def test1(self): - pool = coros.CoroutinePool(max_size=10) - waiters = [] - for i in range(0,9): - waiters.append(pool.execute(sender_loop,i)) - for waiter in waiters: - waiter.wait() - - -if __name__ == '__main__': - tests.main() diff --git a/eventlet/.svn/text-base/twistedsupport.py.svn-base b/eventlet/.svn/text-base/twistedsupport.py.svn-base deleted file mode 100644 index 5bbbc8b..0000000 --- a/eventlet/.svn/text-base/twistedsupport.py.svn-base +++ /dev/null @@ -1,134 +0,0 @@ -"""\ -@file twistedsupport.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().runloop.run() - - def stop(self): - self._stopper.cancel() - posixbase.PosixReactorBase.stop(self) - api.get_hub().remove_descriptor(self._readers.keys()[0]) - api.get_hub().runloop.abort() - - def addReader(self, reader): - fileno = reader.fileno() - self._readers[fileno] = reader - api.get_hub().add_descriptor(fileno, read=self._got_read) - - def _got_read(self, fileno): - self._readers[fileno].doRead() - - def addWriter(self, writer): - fileno = writer.fileno() - self._writers[fileno] = writer - api.get_hub().add_descriptor(fileno, write=self._got_write) - - def _got_write(self, fileno): - self._writers[fileno].doWrite() - - def removeReader(self, reader): - fileno = reader.fileno() - if fileno in self._readers: - self._readers.pop(fileno) - api.get_hub().remove_descriptor(fileno) - - def removeWriter(self, writer): - 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 emulate(): - if not _working: - raise RuntimeError, "Can't use twistedsupport because zope.interface is not installed." - reactor = EventletReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - - -__all__ = ['emulate'] - diff --git a/eventlet/.svn/text-base/util.py.svn-base b/eventlet/.svn/text-base/util.py.svn-base deleted file mode 100644 index 657716c..0000000 --- a/eventlet/.svn/text-base/util.py.svn-base +++ /dev/null @@ -1,214 +0,0 @@ -"""\ -@file util.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. -""" - -import os -import fcntl -import socket -import errno -from errno import EWOULDBLOCK, EAGAIN - -try: - from OpenSSL import SSL -except ImportError: - class SSL(object): - class WantWriteError(object): - pass - - class WantReadError(object): - pass - - class ZeroReturnError(object): - pass - - class SysCallError(object): - pass - - -def g_log(*args): - import sys - import greenlet - from eventlet.greenlib import greenlet_id - g_id = greenlet_id() - if g_id is None: - if greenlet.getcurrent().parent is None: - ident = 'greenlet-main' - else: - g_id = id(greenlet.getcurrent()) - if g_id < 0: - g_id += 1 + ((sys.maxint + 1) << 1) - ident = '%08X' % (g_id,) - else: - ident = 'greenlet-%d' % (g_id,) - print >>sys.stderr, '[%s] %s' % (ident, ' '.join(map(str, args))) - -CONNECT_ERR = (errno.EINPROGRESS, errno.EALREADY, EWOULDBLOCK) -CONNECT_SUCCESS = (0, errno.EISCONN) -def socket_connect(descriptor, address): - err = descriptor.connect_ex(address) - if err in CONNECT_ERR: - return None - if err not in CONNECT_SUCCESS: - raise socket.error(err, errno.errorcode[err]) - return descriptor - -__original_socket__ = socket.socket - -def tcp_socket(): - s = __original_socket__(socket.AF_INET, socket.SOCK_STREAM) - set_nonblocking(s) - return s - - -__original_ssl__ = socket.ssl - - -def wrap_ssl(sock, certificate=None, private_key=None): - from OpenSSL import SSL - from eventlet import wrappedfd, util - context = SSL.Context(SSL.SSLv23_METHOD) - print certificate, private_key - if certificate is not None: - context.use_certificate_file(certificate) - if private_key is not None: - context.use_privatekey_file(private_key) - context.set_verify(SSL.VERIFY_NONE, lambda *x: True) - - ## TODO only do this on client sockets? how? - connection = SSL.Connection(context, sock) - connection.set_connect_state() - return wrappedfd.wrapped_fd(connection) - - -def wrap_socket_with_coroutine_socket(): - def new_socket(*args, **kw): - from eventlet import wrappedfd - s = __original_socket__(*args, **kw) - set_nonblocking(s) - return wrappedfd.wrapped_fd(s) - socket.socket = new_socket - - socket.ssl = wrap_ssl - - -def socket_bind_and_listen(descriptor, addr=('', 0), backlog=50): - set_reuse_addr(descriptor) - descriptor.bind(addr) - descriptor.listen(backlog) - return descriptor - -def socket_accept(descriptor): - try: - return descriptor.accept() - except socket.error, e: - if e[0] == EWOULDBLOCK: - return None - raise - -def socket_send(descriptor, data): - try: - return descriptor.send(data) - except socket.error, e: - if e[0] == EWOULDBLOCK: - return 0 - raise - except SSL.WantWriteError: - return 0 - except SSL.WantReadError: - return 0 - - -# winsock sometimes throws ENOTCONN -SOCKET_CLOSED = (errno.ECONNRESET, errno.ENOTCONN, errno.ESHUTDOWN) -def socket_recv(descriptor, buflen): - try: - return descriptor.recv(buflen) - except socket.error, e: - if e[0] == EWOULDBLOCK: - return None - if e[0] in SOCKET_CLOSED: - return '' - raise - except SSL.WantReadError: - return None - except SSL.ZeroReturnError: - return '' - except SSL.SysCallError, e: - if e[0] == -1 or e[0] > 0: - raise socket.error(errno.ECONNRESET, errno.errorcode[errno.ECONNRESET]) - raise - - -def file_recv(fd, buflen): - try: - return fd.read(buflen) - except IOError, e: - if e[0] == EAGAIN: - return None - return '' - except socket.error, e: - if e[0] == errno.EPIPE: - return '' - raise - - -def file_send(fd, data): - try: - fd.write(data) - fd.flush() - return len(data) - except IOError, e: - if e[0] == EAGAIN: - return 0 - except ValueError, e: - written = 0 - except socket.error, e: - if e[0] == errno.EPIPE: - written = 0 - - -def set_reuse_addr(descriptor): - try: - descriptor.setsockopt( - socket.SOL_SOCKET, - socket.SO_REUSEADDR, - descriptor.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) | 1, - ) - except socket.error: - pass - -def set_nonblocking(descriptor): - if hasattr(descriptor, 'setblocking'): - # socket - descriptor.setblocking(0) - else: - # fd - if hasattr(descriptor, 'fileno'): - fd = descriptor.fileno() - else: - fd = descriptor - flags = fcntl.fcntl(fd, fcntl.F_GETFL) - fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) - return descriptor - diff --git a/eventlet/.svn/text-base/wrappedfd.py.svn-base b/eventlet/.svn/text-base/wrappedfd.py.svn-base deleted file mode 100644 index 21265fb..0000000 --- a/eventlet/.svn/text-base/wrappedfd.py.svn-base +++ /dev/null @@ -1,284 +0,0 @@ -"""\ -@file wrappedfd.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. -""" -from eventlet.api import trampoline, get_hub -from eventlet import util - -BUFFER_SIZE = 4096 - -import socket, errno - - -def higher_order_recv(recv_func): - def recv(self, buflen): - buf = self.recvbuffer - if buf: - chunk, self.recvbuffer = buf[:buflen], buf[buflen:] - return chunk - fd = self.fd - bytes = recv_func(fd, buflen) - while bytes is None: - try: - trampoline(fd, read=True) - except socket.error, e: - if e[0] == errno.EPIPE: - bytes = '' - else: - raise - else: - bytes = recv_func(fd, buflen) - self.recvcount += len(bytes) - return bytes - return recv - - -def higher_order_send(send_func): - def send(self, data): - count = send_func(self.fd, data) - if not count: - return 0 - self.sendcount += count - return count - return send - - - -class RefCount(object): - def __init__(self): - self._count = 1 - - def increment(self): - self._count += 1 - - def decrement(self): - self._count -= 1 - assert self._count >= 0 - - def is_referenced(self): - return self._count > 0 - -class wrapped_fd(object): - newlines = '\r\n' - mode = 'wb+' - is_secure = False - - def __init__(self, fd, refcount = None): - self._closed = False - self.fd = fd - self._fileno = fd.fileno() - self.recvbuffer = '' - self.recvcount = 0 - self.sendcount = 0 - self._refcount = refcount - if refcount is None: - self._refcount = RefCount() - - def getpeername(self, *args, **kw): - fn = self.getpeername = self.fd.getpeername - return fn(*args, **kw) - - def getsockname(self, *args, **kw): - fn = self.getsockname = self.fd.getsockname - return fn(*args, **kw) - - def listen(self, *args, **kw): - fn = self.listen = self.fd.listen - return fn(*args, **kw) - - def bind(self, *args, **kw): - fn = self.bind = self.fd.bind - return fn(*args, **kw) - - def getsockopt(self, *args, **kw): - fn = self.getsockopt = self.fd.getsockopt - return fn(*args, **kw) - - def setsockopt(self, *args, **kw): - fn = self.setsockopt = self.fd.setsockopt - return fn(*args, **kw) - - def connect_ex(self, *args, **kw): - fn = self.connect_ex = self.fd.connect_ex - return fn(*args, **kw) - - def fileno(self, *args, **kw): - fn = self.fileno = self.fd.fileno - return fn(*args, **kw) - - def setblocking(self, *args, **kw): - fn = self.setblocking = self.fd.setblocking - return fn(*args, **kw) - - def close(self, *args, **kw): - if self._closed: - return - self._refcount.decrement() - if self._refcount.is_referenced(): - return - self._closed = True - fn = self.close = self.fd.close - try: - res = fn(*args, **kw) - finally: - # This will raise socket.error(32, 'Broken pipe') if there's - # a caller waiting on trampoline (e.g. server on .accept()) - get_hub().exc_descriptor(self._fileno) - return res - - def accept(self): - fd = self.fd - while True: - res = util.socket_accept(fd) - if res is not None: - client, addr = res - util.set_nonblocking(client) - return type(self)(client), addr - trampoline(fd, read=True, write=True) - - def connect(self, address): - fd = self.fd - connect = util.socket_connect - while not connect(fd, address): - trampoline(fd, read=True, write=True) - - recv = higher_order_recv(util.socket_recv) - - def recvfrom(self, *args): - trampoline(self.fd, read=True) - return self.fd.recvfrom(*args) - - send = higher_order_send(util.socket_send) - - def sendto(self, *args): - trampoline(self.fd, write=True) - return self.fd.sendto(*args) - - def sendall(self, data): - fd = self.fd - tail = self.send(data) - while tail < len(data): - trampoline(self.fd, write=True) - tail += self.send(data[tail:]) - - def write(self, data): - return self.sendall(data) - - def readuntil(self, terminator, size=None): - buf, self.recvbuffer = self.recvbuffer, '' - checked = 0 - if size is None: - while True: - found = buf.find(terminator, checked) - if found != -1: - found += len(terminator) - chunk, self.recvbuffer = buf[:found], buf[found:] - return chunk - checked = max(0, len(buf) - (len(terminator) - 1)) - d = self.recv(BUFFER_SIZE) - if not d: - break - buf += d - return buf - while len(buf) < size: - found = buf.find(terminator, checked) - if found != -1: - found += len(terminator) - chunk, self.recvbuffer = buf[:found], buf[found:] - return chunk - checked = len(buf) - d = self.recv(BUFFER_SIZE) - if not d: - break - buf += d - chunk, self.recvbuffer = buf[:size], buf[size:] - return chunk - - def readline(self, size=None): - return self.readuntil(self.newlines, size=size) - - def __iter__(self): - return self.xreadlines() - - def readlines(self, size=None): - return list(self.xreadlines(size=size)) - - def xreadlines(self, size=None): - if size is None: - while True: - line = self.readline() - if not line: - break - yield line - else: - while size > 0: - line = self.readline(size) - if not line: - break - yield line - size -= len(line) - - def writelines(self, lines): - for line in lines: - self.write(line) - - def read(self, size=None): - if size is not None and not isinstance(size, (int, long)): - raise TypeError('Expecting an int or long for size, got %s: %s' % (type(size), repr(size))) - buf, self.recvbuffer = self.recvbuffer, '' - lst = [buf] - if size is None: - while True: - d = self.recv(BUFFER_SIZE) - if not d: - break - lst.append(d) - else: - buflen = len(buf) - while buflen < size: - d = self.recv(BUFFER_SIZE) - if not d: - break - buflen += len(d) - lst.append(d) - else: - d = lst[-1] - overbite = buflen - size - if overbite: - lst[-1], self.recvbuffer = d[:-overbite], d[-overbite:] - else: - lst[-1], self.recvbuffer = d, '' - return ''.join(lst) - - def makefile(self, *args, **kw): - self._refcount.increment() - return type(self)(self.fd, refcount = self._refcount) - - -class wrapped_file(wrapped_fd): - recv = higher_order_recv(util.file_recv) - - send = higher_order_send(util.file_send) - - def flush(self): - self.fd.flush() diff --git a/eventlet/.svn/text-base/wsgi.py.svn-base b/eventlet/.svn/text-base/wsgi.py.svn-base deleted file mode 100644 index 2fa765a..0000000 --- a/eventlet/.svn/text-base/wsgi.py.svn-base +++ /dev/null @@ -1,219 +0,0 @@ -"""\ -@file wsgi.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. -""" - -import sys -import time -import urllib -import socket -import cStringIO -import SocketServer -import BaseHTTPServer - -from eventlet import api -from eventlet.httpdate import format_date_time - -class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): - - def log_message(self, format, *args): - self.server.log_message("%s - - [%s] %s" % ( - self.address_string(), - self.log_date_time_string(), - format % args)) - - def handle_one_request(self): - self.raw_requestline = self.rfile.readline() - - if not self.raw_requestline: - self.close_connection = 1 - return - - if not self.parse_request(): - return - - self.environ = self.get_environ() - try: - self.handle_one_response() - except socket.error, e: - # Broken pipe, connection reset by peer - if e[0] in (32, 54): - pass - else: - raise - - def handle_one_response(self): - headers_set = [] - headers_sent = [] - # set of lowercase header names that were sent - header_dict = {} - - wfile = self.wfile - num_blocks = None - - def write(data, _write=wfile.write): - if not headers_set: - raise AssertionError("write() before start_response()") - elif not headers_sent: - status, response_headers = headers_set - headers_sent.append(1) - for k, v in response_headers: - header_dict[k.lower()] = k - _write('HTTP/1.0 %s\r\n' % status) - # send Date header? - if 'date' not in header_dict: - _write('Date: %s\r\n' % (format_date_time(time.time()),)) - if 'content-length' not in header_dict and num_blocks == 1: - _write('Content-Length: %s\r\n' % (len(data),)) - for header in response_headers: - _write('%s: %s\r\n' % header) - _write('\r\n') - _write(data) - - def start_request(status, response_headers, exc_info=None): - if exc_info: - try: - if headers_sent: - # Re-raise original exception if headers sent - raise exc_info[0], exc_info[1], exc_info[2] - finally: - # Avoid dangling circular ref - exc_info = None - elif headers_set: - raise AssertionError("Headers already set!") - - headers_set[:] = [status, response_headers] - return write - - result = self.server.app(self.environ, start_request) - try: - num_blocks = len(result) - except (TypeError, AttributeError, NotImplementedError): - pass - - try: - for data in result: - if data: - write(data) - if not headers_sent: - write('') - finally: - if hasattr(result, 'close'): - result.close() - - def get_environ(self): - env = self.server.get_environ() - env['REQUEST_METHOD'] = self.command - env['SCRIPT_NAME'] = '' - - if '?' in self.path: - path, query = self.path.split('?', 1) - else: - path, query = self.path, '' - env['PATH_INFO'] = urllib.unquote(path) - env['QUERY_STRING'] = query - - if self.headers.typeheader is None: - env['CONTENT_TYPE'] = self.headers.type - else: - env['CONTENT_TYPE'] = self.headers.typeheader - - length = self.headers.getheader('content-length') - if length: - env['CONTENT_LENGTH'] = length - env['SERVER_PROTOCOL'] = 'HTTP/1.0' - - host, port = self.request.getsockname() - env['SERVER_NAME'] = host - env['SERVER_PORT'] = str(port) - env['REMOTE_ADDR'] = self.client_address[0] - env['GATEWAY_INTERFACE'] = 'CGI/1.1' - - for h in self.headers.headers: - k, v = h.split(':', 1) - k = k.replace('-', '_').upper() - v = v.strip() - if k in env: - continue - envk = 'HTTP_' + k - if envk in env: - env[envk] += ',' + v - else: - env[envk] = v - - return env - - def finish(self): - # Override SocketServer.StreamRequestHandler.finish because - # we only need to call close on the socket, not the makefile'd things - - self.request.close() - - -class Server(BaseHTTPServer.HTTPServer): - def __init__(self, socket, address, app, log, environ=None): - self.socket = socket - self.address = address - if log: - self.log = log - log.write = log.info - else: - self.log = sys.stderr - self.app = app - self.environ = environ - - def get_environ(self): - socket = self.socket - d = { - 'wsgi.input': socket, - 'wsgi.errors': sys.stderr, - 'wsgi.version': (1, 0), - 'wsgi.multithread': True, - 'wsgi.multiprocess': False, - 'wsgi.run_once': False, - 'wsgi.url_scheme': 'http', - } - if self.environ is not None: - d.update(self.environ) - return d - - def process_request(self, (socket, address)): - proto = HttpProtocol(socket, address, self) - - def log_message(self, message): - self.log.write(message + '\n') - - -def server(socket, site, log=None, environ=None): - serv = Server(socket, socket.getsockname(), site, log, environ=None) - try: - print "wsgi starting up on", socket.getsockname() - while True: - try: - api.spawn(serv.process_request, socket.accept()) - except KeyboardInterrupt: - api.get_hub().remove_descriptor(socket.fileno()) - print "wsgi exiting" - break - finally: - socket.close() diff --git a/eventlet/.svn/tmp/tempfile.2.tmp b/eventlet/.svn/tmp/tempfile.2.tmp deleted file mode 100644 index 7d73756..0000000 --- a/eventlet/.svn/tmp/tempfile.2.tmp +++ /dev/null @@ -1,584 +0,0 @@ -"""\ -@file httpd.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 cgi -import errno -import socket -import sys -import time -import urllib -import socket -import traceback -import BaseHTTPServer - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -from eventlet import api -from eventlet import coros - - -DEFAULT_MAX_HTTP_VERSION = 'HTTP/1.1' - -USE_ACCESS_LOG = True - - -CONNECTION_CLOSED = (errno.EPIPE, errno.ECONNRESET) - - -class ErrorResponse(Exception): - _responses = BaseHTTPServer.BaseHTTPRequestHandler.responses - - def __init__(self, code, reason_phrase=None, headers=None, body=None): - Exception.__init__(self, reason_phrase) - self.code = code - if reason_phrase is None: - self.reason = self._responses[code][0] - else: - self.reason = reason_phrase - self.headers = headers - if body is None: - self.body = self._responses[code][1] - else: - self.body = body - - -class Request(object): - _method = None - _path = None - _responsecode = 200 - _reason_phrase = None - _request_started = False - _chunked = False - _producer_adapters = {} - depth = 0 - def __init__(self, protocol, method, path, headers): - self.context = {} - self.request_start_time = time.time() - self.site = protocol.server.site - self.protocol = protocol - self._method = method - if '?' in path: - self._path, self._query = path.split('?', 1) - self._query = self._query.replace('&', '&') - else: - self._path, self._query = path, None - self._incoming_headers = headers - self._outgoing_headers = dict() - - def response(self, code, reason_phrase=None, headers=None, body=None): - """Change the response code. This will not be sent until some - data is written; last call to this method wins. Default is - 200 if this is not called. - """ - self._responsecode = code - self._reason_phrase = reason_phrase - self.protocol.set_response_code(self, code, reason_phrase) - if headers is not None: - try: - headers = headers.iteritems() - except AttributeError: - pass - for key, value in headers: - self.set_header(key, value) - if body is not None: - self.write(body) - - def is_okay(self): - return 200 <= self._responsecode <= 299 - - def full_url(self): - path = self.path() - query = self.query() - if query: - path = path + '?' + query - - via = self.get_header('via', '') - if via.strip(): - next_part = iter(via.split()).next - - received_protocol = next_part() - received_by = next_part() - if received_by.endswith(','): - received_by = received_by[:-1] - else: - comment = '' - while not comment.endswith(','): - try: - comment += next_part() - except StopIteration: - comment += ',' - break - comment = comment[:-1] - else: - received_by = self.get_header('host') - - return '%s://%s%s' % (self.request_protocol(), received_by, path) - - def begin_response(self, length="-"): - """Begin the response, and return the initial response text - """ - self._request_started = True - request_time = time.time() - self.request_start_time - - code = self._responsecode - proto = self.protocol - - if USE_ACCESS_LOG: - proto.server.write_access_log_line( - proto.client_address[0], - time.strftime("%d/%b/%Y %H:%M:%S"), - proto.requestline, - code, - length, - request_time) - - if self._reason_phrase is not None: - message = self._reason_phrase.split("\n")[0] - elif code in proto.responses: - message = proto.responses[code][0] - else: - message = '' - if proto.request_version == 'HTTP/0.9': - return [] - - response_lines = proto.generate_status_line() - - if not self._outgoing_headers.has_key('connection'): - con = self.get_header('connection') - if con is None and proto.request_version == 'HTTP/1.0': - con = 'close' - if con is not None: - self.set_header('connection', con) - - for key, value in self._outgoing_headers.items(): - key = '-'.join([x.capitalize() for x in key.split('-')]) - response_lines.append("%s: %s" % (key, value)) - - response_lines.append("") - return response_lines - - def write(self, obj): - """Writes an arbitrary object to the response, using - the sitemap's adapt method to convert it to bytes. - """ - if isinstance(obj, str): - self._write_bytes(obj) - elif isinstance(obj, unicode): - # use utf8 encoding for now, *TODO support charset negotiation - # Content-Type: text/html; charset=utf-8 - ctype = self._outgoing_headers.get('content-type', 'text/html') - ctype = ctype + '; charset=utf-8' - self._outgoing_headers['content-type'] = ctype - self._write_bytes(obj.encode('utf8')) - else: - self.site.adapt(obj, self) - - def _write_bytes(self, data): - """Write all the data of the response. - Can be called just once. - """ - if self._request_started: - print "Request has already written a response:" - traceback.print_stack() - return - - self._outgoing_headers['content-length'] = len(data) - - response_lines = self.begin_response(len(data)) - response_lines.append(data) - self.protocol.wfile.write("\r\n".join(response_lines)) - if hasattr(self.protocol.wfile, 'flush'): - self.protocol.wfile.flush() - - def method(self): - return self._method - - def path(self): - return self._path - - def path_segments(self): - return [urllib.unquote_plus(x) for x in self._path.split('/')[1:]] - - def query(self): - return self._query - - def uri(self): - if self._query: - return '%s?%s' % ( - self._path, self._query) - return self._path - - def get_headers(self): - return self._incoming_headers - - def get_header(self, header_name, default=None): - return self.get_headers().get(header_name.lower(), default) - - def get_query_pairs(self): - if not hasattr(self, '_split_query'): - if self._query is None: - self._split_query = () - else: - spl = self._query.split('&') - spl = [x.split('=', 1) for x in spl if x] - self._split_query = [] - for query in spl: - if len(query) == 1: - key = query[0] - value = '' - else: - key, value = query - self._split_query.append((urllib.unquote_plus(key), urllib.unquote_plus(value))) - - return self._split_query - - def get_queries_generator(self, name): - """Generate all query parameters matching the given name. - """ - for key, value in self.get_query_pairs(): - if key == name or not name: - yield value - - get_queries = lambda self, name: list(self.get_queries_generator) - - def get_query(self, name, default=None): - try: - return self.get_queries_generator(name).next() - except StopIteration: - return default - - def get_arg_list(self, name): - return self.get_field_storage().getlist(name) - - def get_arg(self, name, default=None): - return self.get_field_storage().getfirst(name, default) - - def get_field_storage(self): - if not hasattr(self, '_field_storage'): - if self.method() == 'GET': - data = '' - if self._query: - data = self._query - else: - data = self.read_body() - fl = StringIO(data) - ## Allow our resource to provide the FieldStorage instance for - ## customization purposes. - headers = self.get_headers() - environ = dict( - REQUEST_METHOD='POST', - QUERY_STRING=self._query or '') - - self._field_storage = cgi.FieldStorage(fl, headers, environ=environ) - - return self._field_storage - - def set_header(self, key, value): - if key.lower() == 'connection' and value.lower() == 'close': - self.protocol.close_connection = 1 - self._outgoing_headers[key.lower()] = value - __setitem__ = set_header - - def get_outgoing_header(self, key): - return self._outgoing_headers[key.lower()] - - def has_outgoing_header(self, key): - return self._outgoing_headers.has_key(key.lower()) - - def socket(self): - return self.protocol.socket - - def error(self, response=None, body=None, log_traceback=True): - if log_traceback: - traceback.print_exc(file=self.log) - if response is None: - response = 500 - if body is None: - typ, val, tb = sys.exc_info() - body = dict(type=str(typ), error=True, reason=str(val)) - self.response(response) - if(type(body) is str and not self.response_written()): - self.write(body) - return - try: - produce(body, self) - except Exception, e: - traceback.print_exc(file=self.log) - if not self.response_written(): - self.write('Internal Server Error') - - def not_found(self): - self.error(404, 'Not Found\n', log_traceback=False) - - def raw_body(self): - if not hasattr(self, '_cached_body'): - self.read_body() - return self._cached_body - - def read_body(self): - """ Returns the string body that was read off the request, or - the empty string if there was no request body. - - Requires a content-length header. Caches the body so multiple - calls to read_body() are free. - """ - if not hasattr(self, '_cached_body'): - length = self.get_header('content-length') - if length: - length = int(length) - if length: - self._cached_body = self.protocol.rfile.read(length) - else: - self._cached_body = '' - return self._cached_body - - def parsed_body(self): - """ Returns the parsed version of the body, using the - content-type header to select from the parsers on the site - object. - - If no parser is found, returns the string body from - read_body(). Caches the parsed body so multiple calls to - parsed_body() are free. - """ - if not hasattr(self, '_cached_parsed_body'): - body = self.read_body() - if hasattr(self.site, 'parsers'): - parser = self.site.parsers.get( - self.get_header('content-type')) - if parser is not None: - body = parser(body) - self._cached_parsed_body = body - return self._cached_parsed_body - - def override_body(self, body): - if not hasattr(self, '_cached_parsed_body'): - self.read_body() ## Read and discard body - self._cached_parsed_body = body - - def response_written(self): - ## TODO change badly named variable - return self._request_started - - def request_version(self): - return self.protocol.request_version - - def request_protocol(self): - if self.protocol.socket.is_secure: - return "https" - return "http" - - def server_address(self): - return self.protocol.server.address - - def __repr__(self): - return "" % ( - getattr(self, '_method'), getattr(self, '_path')) - -DEFAULT_TIMEOUT = 300 - -# This value was chosen because apache 2 has a default limit of 8190. -# I believe that slightly smaller number is because apache does not -# count the \r\n. -MAX_REQUEST_LINE = 8192 - -class Timeout(RuntimeError): - pass - -class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): - def __init__(self, request, client_address, server): - self.socket = self.request = self.rfile = self.wfile = request - self.client_address = client_address - self.server = server - self.set_response_code(None, 200, None) - self.protocol_version = server.max_http_version - - def set_response_code(self, request, code, message): - self._code = code - if message is not None: - self._message = message.split("\n")[0] - elif code in self.responses: - self._message = self.responses[code][0] - else: - self._message = '' - - def generate_status_line(self): - return [ - "%s %d %s" % ( - self.protocol_version, self._code, self._message)] - - def write_bad_request(self, status, reason): - self.set_response_code(self, status, reason) - self.wfile.write(''.join(self.generate_status_line())) - self.wfile.write('\r\nServer: %s\r\n' % self.version_string()) - self.wfile.write('Date: %s\r\n' % self.date_time_string()) - self.wfile.write('Content-Length: 0\r\n\r\n') - - def handle(self): - self.close_connection = 0 - - timeout = DEFAULT_TIMEOUT - while not self.close_connection: - if timeout == 0: - break - cancel = api.exc_after(timeout, Timeout) - try: - self.raw_requestline = self.rfile.readline(MAX_REQUEST_LINE) - if self.raw_requestline is not None: - if len(self.raw_requestline) == MAX_REQUEST_LINE: - # Someone sent a request line which is too - # large. Be helpful and tell them. - self.write_bad_request(414, 'Request-URI Too Long') - self.close_connection = True - continue - except socket.error, e: - if e[0] in CONNECTION_CLOSED: - self.close_connection = True - cancel.cancel() - continue - except Timeout: - self.close_connection = True - continue - except Exception, e: - try: - if e[0][0][0].startswith('SSL'): - print "SSL Error:", e[0][0] - self.close_connection = True - cancel.cancel() - continue - except Exception, f: - print "Exception in ssl test:",f - pass - raise e - cancel.cancel() - - if not self.raw_requestline or not self.parse_request(): - self.close_connection = True - continue - - self.set_response_code(None, 200, None) - request = Request(self, self.command, self.path, self.headers) - request.set_header('Server', self.version_string()) - request.set_header('Date', self.date_time_string()) - try: - timeout = int(request.get_header('keep-alive', timeout)) - except TypeError, ValueError: - pass - - try: - try: - try: - self.server.site.handle_request(request) - except ErrorResponse, err: - request.response(code=err.code, - reason_phrase=err.reason, - headers=err.headers, - body=err.body) - finally: - # clean up any timers that might have been left around by the handling code - api.get_hub().runloop.cancel_timers(api.getcurrent()) - - # throw an exception if it failed to write a body - if not request.response_written(): - raise NotImplementedError("Handler failed to write response to request: %s" % request) - - if not hasattr(self, '_cached_body'): - try: - request.read_body() ## read & discard body - except: - pass - - except socket.error, e: - # Broken pipe, connection reset by peer - if e[0] in CONNECTION_CLOSED: - #print "Remote host closed connection before response could be sent" - pass - else: - raise - except Exception, e: - self.server.log_message("Exception caught in HttpRequest.handle():\n") - self.server.log_exception(*sys.exc_info()) - if not request.response_written(): - request.response(500) - request.write('Internal Server Error') - self.socket.close() - raise e # can't do a plain raise since exc_info might have been cleared - self.socket.close() - - -class Server(BaseHTTPServer.HTTPServer): - def __init__(self, socket, address, site, log, max_http_version=DEFAULT_MAX_HTTP_VERSION): - self.socket = socket - self.address = address - self.site = site - self.max_http_version = max_http_version - if log: - self.log = log - if hasattr(log, 'info'): - log.write = log.info - else: - self.log = self - - def write(self, something): - sys.stdout.write('%s' % (something, )); sys.stdout.flush() - - def log_message(self, message): - self.log.write(message) - - def log_exception(self, type, value, tb): - self.log.write(''.join(traceback.format_exception(type, value, tb))) - - def write_access_log_line(self, *args): - """Write a line to the access.log. Arguments: - client_address, date_time, requestline, code, size, request_time - """ - self.log.write( - '%s - - [%s] "%s" %s %s %.6f\n' % args) - - -def server(sock, site, log=None, max_size=512, serv=None, max_http_version=DEFAULT_MAX_HTTP_VERSION): - pool = coros.CoroutinePool(max_size=max_size) - if serv is None: - serv = Server(sock, sock.getsockname(), site, log, max_http_version=max_http_version) - try: - serv.log.write("httpd starting up on %s\n" % (sock.getsockname(), )) - while True: - try: - new_sock, address = sock.accept() - proto = HttpProtocol(new_sock, address, serv) - pool.execute_async(proto.handle) - api.sleep(0) # sleep to allow other coros to run - except KeyboardInterrupt: - api.get_hub().remove_descriptor(sock.fileno()) - serv.log.write("httpd exiting\n") - break - finally: - try: - sock.close() - except socket.error: - pass diff --git a/examples/.svn/all-wcprops b/examples/.svn/all-wcprops deleted file mode 100644 index 8bd82e5..0000000 --- a/examples/.svn/all-wcprops +++ /dev/null @@ -1,17 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 39 -/svn/eventlet/!svn/ver/3/trunk/examples -END -webcrawler.py -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/eventlet/!svn/ver/3/trunk/examples/webcrawler.py -END -echoserver.py -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/eventlet/!svn/ver/3/trunk/examples/echoserver.py -END diff --git a/examples/.svn/entries b/examples/.svn/entries deleted file mode 100644 index b1283ae..0000000 --- a/examples/.svn/entries +++ /dev/null @@ -1,54 +0,0 @@ -8 - -dir -100 -https://svn.secondlife.com/svn/eventlet/trunk/examples -https://svn.secondlife.com/svn/eventlet - - - -2007-08-23T23:57:41.609100Z -3 -which.linden - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -cde37729-5338-0410-b9e2-c56166a61366 - -webcrawler.py -file - - - - -2008-02-20T19:57:15.000000Z -d97f9983eb0eb98eddc66259f2abb82d -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - -echoserver.py -file - - - - -2008-02-20T19:57:15.000000Z -ee5d6fb335a4a28b2b9af8ae3fdca660 -2007-08-23T23:51:23.835123Z -1 -which.linden -has-props - diff --git a/examples/.svn/format b/examples/.svn/format deleted file mode 100644 index 45a4fb7..0000000 --- a/examples/.svn/format +++ /dev/null @@ -1 +0,0 @@ -8 diff --git a/examples/.svn/prop-base/echoserver.py.svn-base b/examples/.svn/prop-base/echoserver.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/examples/.svn/prop-base/echoserver.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/examples/.svn/prop-base/webcrawler.py.svn-base b/examples/.svn/prop-base/webcrawler.py.svn-base deleted file mode 100644 index bdbd305..0000000 --- a/examples/.svn/prop-base/webcrawler.py.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:eol-style -V 6 -native -END diff --git a/examples/.svn/text-base/echoserver.py.svn-base b/examples/.svn/text-base/echoserver.py.svn-base deleted file mode 100644 index 3fe0191..0000000 --- a/examples/.svn/text-base/echoserver.py.svn-base +++ /dev/null @@ -1,52 +0,0 @@ -"""\ -@file echoserver.py - -Simple server that listens on port 6000 and echos back every input to -the client. To try out the server, start it up by running this file. - -Connect to it with: - telnet localhost 6000 - -You terminate your connection by terminating telnet (typically Ctrl-] -and then 'quit') - -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 import api - -def handle_socket(client): - print "client connected" - while True: - # pass through every non-eof line - x = client.readline() - if not x: break - client.write(x) - print "echoed", x - print "client disconnected" - -# server socket listening on port 6000 -server = api.tcp_listener(('0.0.0.0', 6000)) -while True: - new_sock, address = server.accept() - # handle every new connection with a new coroutine - api.spawn(handle_socket, new_sock) - -server.close() diff --git a/examples/.svn/text-base/webcrawler.py.svn-base b/examples/.svn/text-base/webcrawler.py.svn-base deleted file mode 100644 index 27c9c40..0000000 --- a/examples/.svn/text-base/webcrawler.py.svn-base +++ /dev/null @@ -1,55 +0,0 @@ -"""\ -@file webcrawler.py - -This is a simple web "crawler" that fetches a bunch of urls using a coroutine pool. It fetches as - many urls at time as coroutines in the pool. - -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. -""" - -urls = ["http://www.google.com/intl/en_ALL/images/logo.gif", - "http://wiki.secondlife.com/w/images/secondlife.jpg", - "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif"] - -import time -from eventlet import coros, httpc, util - -# replace socket with a cooperative coroutine socket because httpc -# uses httplib, which uses socket. Removing this serializes the http -# requests, because the standard socket is blocking. -util.wrap_socket_with_coroutine_socket() - -def fetch(url): - # we could do something interesting with the result, but this is - # example code, so we'll just report that we did it - print "%s fetching %s" % (time.asctime(), url) - httpc.get(url) - print "%s fetched %s" % (time.asctime(), url) - -pool = coros.CoroutinePool(max_size=4) -waiters = [] -for url in urls: - waiters.append(pool.execute(fetch, url)) - -# wait for all the coroutines to come back before exiting the process -for waiter in waiters: - waiter.wait() - -