Commits

Daniele Varrazzo committed e03a74f

Added a friendly license

Comments (0)

Files changed (9)

+~$
+\.sw[op]$
+\.pyc$
+\.orig$
+\.rej$
+^lib
-Some testing material to work with Psycopg2 with coroutine support.
+Some testing material to work with Psycopg2 with coroutine_ support.
 
+One of upcoming Psycopg version will have coroutine support. In order to use
+them a coroutine framework, such as Eventlet_ or gevent_, should implement a
+"wait callback" as an hook to schedule a coroutine switch while a libpq call is
+waiting for data.
 
+In this project there are wait callback implementations for a few coroutine
+libraries: they are licensed in order to allow their inclusion in the library.
+
+.. _coroutine: http://en.wikipedia.org/wiki/Coroutine
+.. _Eventlet: http://eventlet.net/
+.. _gevent: http://www.gevent.org/

eventlet/nonblock_eventlet.py

-import eventlet
-eventlet.monkey_patch()
-
-import psyco_eventlet
-psyco_eventlet.make_psycopg_green()
-
-import urllib2  # green
-
-import psycopg2
-
-import logging
-logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
-logger = logging.getLogger()
-logger.info("testing psycopg2 with eventlet")
-
-conn = psycopg2.connect("dbname=postgres")
-
-def download(num, secs):
-    url = "http://localhost:8000/%d/" % secs
-    for i in range(num):
-        logger.info("download %d start", i)
-        data = urllib2.urlopen(url).read()
-        logger.info("download %d end", i)
-
-def fetch(num, secs):
-    cur = conn.cursor()
-    for i in range(num):
-        logger.info("fetch %d start", i)
-        cur.execute("select pg_sleep(%s)", (secs,))
-        logger.info("fetch %d end", i)
-
-logger.info("making jobs")
-pool = eventlet.GreenPool()
-pool.spawn(download, 2, 3),
-pool.spawn(fetch, 3, 2),
-
-logger.info("join begin")
-pool.waitall()
-logger.info("join end")
-
-

eventlet/psyco_eventlet.py

 """A wait callback to allow psycopg2 cooperation with eventlet.
+
+Use `make_psycopg_green()` to enable eventlet support in Psycopg.
 """
+
 # Copyright (C) 2010 Daniele Varrazzo <daniele.varrazzo@gmail.com>
+# and licensed under the MIT license:
+# 
+# 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 psycopg2
 from psycopg2 import extensions
 from eventlet.hubs import trampoline
 
 def make_psycopg_green():
+    """Configure Psycopg to be used with eventlet in non-blocking way."""
     if not hasattr(extensions, 'set_wait_callback'):
         raise ImportError(
             "Support for coroutines is available only from Psycopg 2.2.0")
     extensions.set_wait_callback(eventlet_wait_callback)
 
 def eventlet_wait_callback(conn, timeout=-1):
+    """A wait callback useful to allow eventlet to work with Psycopg."""
     while 1:
         state = conn.poll()
         if state == extensions.POLL_OK:

eventlet/test_eventlet.py

+#!/usr/bin/env python
+"""A test to verify Psycopg collaboration with other blocking I/O.
+
+Please run the script ``tools/wait_server.py`` in a separate shell to make the
+test work.
+
+If the test works you should see download tasks overlapping query tasks.
+"""
+
+# Copyright (C) 2010 Daniele Varrazzo <daniele.varrazzo@gmail.com>
+#
+#  This module is licensed under the MIT license:
+#
+#  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 eventlet
+eventlet.monkey_patch()
+
+import psyco_eventlet
+psyco_eventlet.make_psycopg_green()
+
+import urllib2  # green
+
+import psycopg2
+
+import logging
+logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
+logger = logging.getLogger()
+logger.info("testing psycopg2 with eventlet")
+
+conn = psycopg2.connect("dbname=postgres")
+
+def download(num, secs):
+    url = "http://localhost:8000/%d/" % secs
+    for i in range(num):
+        logger.info("download %d start", i)
+        data = urllib2.urlopen(url).read()
+        logger.info("download %d end", i)
+
+def fetch(num, secs):
+    cur = conn.cursor()
+    for i in range(num):
+        logger.info("query %d start", i)
+        cur.execute("select pg_sleep(%s)", (secs,))
+        logger.info("query %d end", i)
+
+logger.info("making jobs")
+pool = eventlet.GreenPool()
+pool.spawn(download, 2, 3),
+pool.spawn(fetch, 3, 2),
+
+logger.info("join begin")
+pool.waitall()
+logger.info("join end")
+

gevent/nonblock_gevent.py

-import gevent
-import gevent.monkey
-gevent.monkey.patch_all()
-
-import psyco_gevent
-psyco_gevent.make_psycopg_green()
-
-import urllib2  # green
-
-import psycopg2
-
-import logging
-logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
-logger = logging.getLogger()
-logger.info("testing psycopg2 with gevent")
-
-conn = psycopg2.connect("dbname=postgres")
-
-def download(num, secs):
-    url = "http://localhost:8000/%d/" % secs
-    for i in range(num):
-        logger.info("download %d start", i)
-        data = urllib2.urlopen(url).read()
-        logger.info("download %d end", i)
-
-def fetch(num, secs):
-    cur = conn.cursor()
-    for i in range(num):
-        logger.info("fetch %d start", i)
-        cur.execute("select pg_sleep(%s)", (secs,))
-        logger.info("fetch %d end", i)
-
-logger.info("making jobs")
-jobs = [
-    gevent.spawn(download, 2, 3),
-    gevent.spawn(fetch, 3, 2),
-    ]
-
-logger.info("join begin")
-gevent.joinall(jobs)
-logger.info("join end")
-

gevent/psyco_gevent.py

 """A wait callback to allow psycopg2 cooperation with gevent.
+
+Use `make_psycopg_green()` to enable gevent support in Psycopg.
 """
+
 # Copyright (C) 2010 Daniele Varrazzo <daniele.varrazzo@gmail.com>
+# and licensed under the MIT license:
+# 
+# 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 psycopg2
 from psycopg2 import extensions
 from gevent.hub import sleep as gevent_sleep
 
 def make_psycopg_green():
+    """Configure Psycopg to be used with gevent in non-blocking way."""
     if not hasattr(extensions, 'set_wait_callback'):
         raise ImportError(
-            "Support for coroutines is available only from Psycopg 2.2.0")
+            "support for coroutines not available in this Psycopg version (%s)"
+            % psycopg2.__version__)
 
     extensions.set_wait_callback(gevent_wait_callback)
 
     pass
 
 def gevent_wait_callback(conn, timeout=-1):
+    """A wait callback useful to allow gevent to work with Psycopg."""
     while 1:
         state = conn.poll()
         if state == extensions.POLL_OK:

gevent/test_gevent.py

+#!/usr/bin/env python
+"""A test to verify Psycopg collaboration with other blocking I/O.
+
+Please run the script ``tools/wait_server.py`` in a separate shell to make the
+test work.
+
+If the test works you should see download tasks overlapping query tasks.
+"""
+
+# Copyright (C) 2010 Daniele Varrazzo <daniele.varrazzo@gmail.com>
+#
+#  This module is licensed under the MIT license:
+#
+#  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 gevent
+import gevent.monkey
+gevent.monkey.patch_all()
+
+import psyco_gevent
+psyco_gevent.make_psycopg_green()
+
+import urllib2  # green
+
+import psycopg2
+
+import logging
+logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
+logger = logging.getLogger()
+logger.info("testing psycopg2 with gevent")
+
+conn = psycopg2.connect("dbname=postgres")
+
+def download(num, secs):
+    url = "http://localhost:8000/%d/" % secs
+    for i in range(num):
+        logger.info("download %d start", i)
+        data = urllib2.urlopen(url).read()
+        logger.info("download %d end", i)
+
+def fetch(num, secs):
+    cur = conn.cursor()
+    for i in range(num):
+        logger.info("query %d start", i)
+        cur.execute("select pg_sleep(%s)", (secs,))
+        logger.info("query %d end", i)
+
+logger.info("making jobs")
+jobs = [
+    gevent.spawn(download, 2, 3),
+    gevent.spawn(fetch, 3, 2),
+    ]
+
+logger.info("join begin")
+gevent.joinall(jobs)
+logger.info("join end")
+

tools/wait_server.py

-import time
+#!/usr/bin/env python
+"""A server to test with blocking I/O."""
+
+# Copyright (C) 2010 Daniele Varrazzo <daniele.varrazzo@gmail.com>
+# and licensed under the MIT license:
+# 
+# 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
+
 from wsgiref.util import setup_testing_defaults
 from wsgiref.simple_server import make_server