Commits

Daniele Varrazzo committed c7ee508

Converting psycogreen into a package

  • Participants
  • Parent commits 3b92dcd

Comments (0)

Files changed (10)

-Coroutine support for Psycopg
-=============================
+psycogreen -- integrate psycopg2 with coroutine libraries
+=========================================================
 
-Starting from `release 2.2`__, `Psycopg`_ offers `coroutines support`__.
+Since `release 2.2`__, `Psycopg`_ offers `coroutines support`__.
 
 Psycopg is a C extension module, so it can't be monkey-patched to be
 coroutine-friendly. Instead it now exposes `a hook`__
 implement their "wait callaback" in order to have a chance to schedule a
 coroutine switch.
 
-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.
+The psycogreen package is a contained of callbacks to make psycopg2 work with
+coroutine libraries, using asynchronous calls internally but offering a
+blocking interface so that regular code can run unmodified.
+
 
 .. _Psycopg: http://initd.org/psycopg/
 .. __: http://initd.org/psycopg/articles/2010/05/16/psycopg-220-released/

File 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 not available in this Psycopg version (%s)"
-            % psycopg2.__version__)
-
-    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:
-            break
-        elif state == extensions.POLL_READ:
-            trampoline(conn.fileno(), read=True)
-        elif state == extensions.POLL_WRITE:
-            trampoline(conn.fileno(), write=True)
-        else:
-            raise psycopg2.OperationalError(
-                "Bad result from poll: %r" % state)

File 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")
-

File 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.socket import wait_read, wait_write
-
-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 not available in this Psycopg version (%s)"
-            % psycopg2.__version__)
-
-    extensions.set_wait_callback(gevent_wait_callback)
-
-def gevent_wait_callback(conn, timeout=None):
-    """A wait callback useful to allow gevent to work with Psycopg."""
-    while 1:
-        state = conn.poll()
-        if state == extensions.POLL_OK:
-            break
-        elif state == extensions.POLL_READ:
-            wait_read(conn.fileno(), timeout=timeout)
-        elif state == extensions.POLL_WRITE:
-            wait_write(conn.fileno(), timeout=timeout)
-        else:
-            raise psycopg2.OperationalError(
-                "Bad result from poll: %r" % state)

File 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")
-

File psycogreen/__init__.py

+"""Integration of psycopg2 with coroutine framework
+"""
+
+# Copyright (C) 2010-2012 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.
+
+__version__ = '1.0a0'
+

File psycogreen/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.
+
+from __future__ import absolute_import
+
+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 not available in this Psycopg version (%s)"
+            % psycopg2.__version__)
+
+    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:
+            break
+        elif state == extensions.POLL_READ:
+            trampoline(conn.fileno(), read=True)
+        elif state == extensions.POLL_WRITE:
+            trampoline(conn.fileno(), write=True)
+        else:
+            raise psycopg2.OperationalError(
+                "Bad result from poll: %r" % state)

File psycogreen/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.
+
+from __future__ import absolute_import
+
+import psycopg2
+from psycopg2 import extensions
+
+from gevent.socket import wait_read, wait_write
+
+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 not available in this Psycopg version (%s)"
+            % psycopg2.__version__)
+
+    extensions.set_wait_callback(gevent_wait_callback)
+
+def gevent_wait_callback(conn, timeout=None):
+    """A wait callback useful to allow gevent to work with Psycopg."""
+    while 1:
+        state = conn.poll()
+        if state == extensions.POLL_OK:
+            break
+        elif state == extensions.POLL_READ:
+            wait_read(conn.fileno(), timeout=timeout)
+        elif state == extensions.POLL_WRITE:
+            wait_write(conn.fileno(), timeout=timeout)
+        else:
+            raise psycopg2.OperationalError(
+                "Bad result from poll: %r" % state)

File tests/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 psycogreen.eventlet
+psycogreen.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")
+

File tests/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 psycogreen.gevent
+psycogreen.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")
+