diff --git a/aiogremlin/__init__.py b/aiogremlin/__init__.py
index 6b56a30e79f0c6e3e4cadc0207dc91d136789e5e..48332a24203b242857bc873f758473eb601176ce 100644
--- a/aiogremlin/__init__.py
+++ b/aiogremlin/__init__.py
@@ -1,7 +1,9 @@
-from .response import *
-from .client import *
-from .exceptions import *
-from .connector import *
-from .subprotocol import *
+from aiogremlin.driver.cluster import Cluster
+from aiogremlin.remote.driver_remote_connection import DriverRemoteConnection
+from aiogremlin.gremlin_python import statics
+from aiogremlin.gremlin_python.process import strategies
+from aiogremlin.gremlin_python.process.graph_traversal import __
+from aiogremlin.gremlin_python.process.traversal import Binding
+from aiogremlin.gremlin_python.structure.graph import Graph
 
-__version__ = "0.1.1"
+__version__ = "3.2.4"
diff --git a/aiogremlin/client.py b/aiogremlin/client.py
deleted file mode 100644
index 6f4459bf4b3c52a000536389dd95763449de04ec..0000000000000000000000000000000000000000
--- a/aiogremlin/client.py
+++ /dev/null
@@ -1,416 +0,0 @@
-"""Client for the Tinkerpop 3 Gremlin Server."""
-
-import asyncio
-import uuid
-
-import aiohttp
-
-from aiogremlin.response import GremlinClientWebSocketResponse
-from aiogremlin.exceptions import RequestError, GremlinServerError
-from aiogremlin.connector import GremlinConnector
-from aiogremlin.subprotocol import gremlin_response_parser, GremlinWriter
-
-__all__ = ("submit", "GremlinClient", "GremlinClientSession",
-           "GremlinResponse", "GremlinResponseStream")
-
-
-class GremlinClient:
-    """Main interface for interacting with the Gremlin Server.
-
-    :param str url: url for Gremlin Server (optional). 'http://localhost:8182/'
-        by default
-    :param loop: :ref:`event loop<asyncio-event-loop>` If param is ``None``,
-        `asyncio.get_event_loop` is used for getting default event loop
-        (optional)
-    :param str lang: Language of scripts submitted to the server.
-        "gremlin-groovy" by default
-    :param str op: Gremlin Server op argument. "eval" by default.
-    :param str processor: Gremlin Server processor argument. "" by default.
-    :param float timeout: timeout for websocket read (seconds)(optional).
-        Values ``0`` or ``None`` mean no timeout
-    :param ws_connector: A class that implements the method ``ws_connect``.
-        Usually an instance of ``aiogremlin.connector.GremlinConnector``
-    :param float conn_timeout: timeout for establishing connection (seconds)
-        (optional). Values ``0`` or ``None`` mean no timeout
-    :param username: Username for SASL auth
-    :param password: Password for SASL auth
-    """
-
-    def __init__(self, *, url='http://localhost:8182/', loop=None,
-                 lang="gremlin-groovy", op="eval", processor="",
-                 timeout=None, ws_connector=None, client_session=None,
-                 conn_timeout=None, username="", password=""):
-        self._lang = lang
-        self._op = op
-        self._processor = processor
-        self._loop = loop or asyncio.get_event_loop()
-        self._closed = False
-        self._session = None
-        self._url = url
-        self._timeout = timeout
-        self._username = username
-        self._password = password
-        if ws_connector is None:
-            ws_connector = GremlinConnector(loop=self._loop,
-                                            client_session=client_session,
-                                            conn_timeout=conn_timeout)
-        self._connector = ws_connector
-
-    @property
-    def loop(self):
-        """Readonly property that returns event loop used by client"""
-        return self._loop
-
-    @property
-    def op(self):
-        """Readonly property that returns op argument for Gremlin Server"""
-        return self._op
-
-    @property
-    def processor(self):
-        """Readonly property. The processor argument for Gremlin
-        Server"""
-        return self._processor
-
-    @property
-    def lang(self):
-        """Readonly property. The language used for Gremlin scripts"""
-        return self._lang
-
-    @property
-    def url(self):
-        """Getter/setter for database url used by the client"""
-        return self._url
-
-    @url.setter
-    def url(self, value):
-        self._url = value
-
-    @property
-    def closed(self):
-        """Readonly property. Return True if client has been closed"""
-        return self._closed or self._connector is None
-
-    @asyncio.coroutine
-    def close(self):
-        """
-        :ref:`coroutine<coroutine>` method.
-
-        Close client. If client has not been detached from underlying
-        ws_connector, this coroutinemethod closes the latter as well."""
-        if self._closed:
-            return
-        self._closed = True
-        try:
-            yield from self._connector.close()
-        finally:
-            self._connector = None
-
-    def detach(self):
-        """Detach client from ws_connector. Client status is now closed"""
-        self._connector = None
-
-    @asyncio.coroutine
-    def submit(self, gremlin, *, bindings=None, lang=None, rebindings=None,
-               op=None, processor=None, binary=True, session=None,
-               timeout=None):
-        """
-        :ref:`coroutine<coroutine>` method.
-
-        Submit a script to the Gremlin Server.
-
-        :param str gremlin: Gremlin script to submit to server.
-        :param dict bindings: A mapping of bindings for Gremlin script.
-        :param str lang: Language of scripts submitted to the server.
-            "gremlin-groovy" by default
-        :param dict rebindings: Rebind ``Graph`` and ``TraversalSource``
-            objects to different variable names in the current request
-        :param str op: Gremlin Server op argument. "eval" by default.
-        :param str processor: Gremlin Server processor argument. "" by default.
-        :param float timeout: timeout for establishing connection (optional).
-            Values ``0`` or ``None`` mean no timeout
-        :param str session: Session id (optional). Typically a uuid
-        :param loop: :ref:`event loop<asyncio-event-loop>` If param is ``None``
-            `asyncio.get_event_loop` is used for getting default event loop
-            (optional)
-        :returns: :py:class:`aiogremlin.client.GremlinResponse` object
-        """
-        lang = lang or self.lang
-        op = op or self.op
-        processor = processor or self.processor
-        if session is None:
-            session = self._session
-        if timeout is None:
-            timeout = self._timeout
-
-        ws = yield from self._connector.ws_connect(
-            self.url, timeout=timeout)
-
-        writer = GremlinWriter(ws)
-
-        ws = writer.write(gremlin=gremlin, bindings=bindings, lang=lang,
-                          rebindings=rebindings, op=op,
-                          processor=processor, binary=binary,
-                          session=session)
-
-        return GremlinResponse(ws, username=self._username,
-                               password=self._password, session=session,
-                               loop=self._loop)
-
-    @asyncio.coroutine
-    def execute(self, gremlin, *, bindings=None, lang=None, rebindings=None,
-                session=None, op=None, processor=None, binary=True,
-                timeout=None):
-        """
-        :ref:`coroutine<coroutine>` method.
-
-        Submit a script to the Gremlin Server and get the result.
-
-        :param str gremlin: Gremlin script to submit to server.
-        :param dict bindings: A mapping of bindings for Gremlin script.
-        :param str lang: Language of scripts submitted to the server.
-            "gremlin-groovy" by default
-        :param dict rebindings: Rebind ``Graph`` and ``TraversalSource``
-            objects to different variable names in the current request
-        :param str op: Gremlin Server op argument. "eval" by default.
-        :param str processor: Gremlin Server processor argument. "" by default.
-        :param float timeout: timeout for establishing connection (optional).
-            Values ``0`` or ``None`` mean no timeout
-        :param str session: Session id (optional). Typically a uuid
-        :param loop: :ref:`event loop<asyncio-event-loop>` If param is ``None``
-            `asyncio.get_event_loop` is used for getting default event loop
-            (optional)
-        :returns: :py:class:`list` of
-            :py:class:`aiogremlin.subprotocol.Message`
-        """
-        lang = lang or self.lang
-        op = op or self.op
-        processor = processor or self.processor
-        resp = yield from self.submit(gremlin, bindings=bindings, lang=lang,
-                                      rebindings=rebindings, op=op,
-                                      processor=processor, binary=binary,
-                                      session=session, timeout=timeout)
-
-        return (yield from resp.get())
-
-
-class GremlinClientSession(GremlinClient):
-    """Interface for interacting with the Gremlin Server using sessions.
-
-    :param str url: url for Gremlin Server (optional). 'http://localhost:8182/'
-        by default
-    :param loop: :ref:`event loop<asyncio-event-loop>` If param is ``None``,
-        `asyncio.get_event_loop` is used for getting default event loop
-        (optional)
-    :param str lang: Language of scripts submitted to the server.
-        "gremlin-groovy" by default
-    :param str op: Gremlin Server op argument. "eval" by default.
-    :param str processor: Gremlin Server processor argument. "" by default.
-    :param float timeout: timeout for establishing connection (optional).
-        Values ``0`` or ``None`` mean no timeout
-    """
-
-    def __init__(self, *, url='http://localhost:8182/', loop=None,
-                 lang="gremlin-groovy", op="eval", processor="session",
-                 session=None, timeout=None, client_session=None,
-                 ws_connector=None, username="", password=""):
-        super().__init__(url=url, lang=lang, op=op, processor=processor,
-                         loop=loop, timeout=timeout, ws_connector=ws_connector,
-                         client_session=client_session, username=username,
-                         password=password)
-
-        if session is None:
-            session = str(uuid.uuid4())
-        self._session = session
-
-    @property
-    def session(self):
-        """Getter setter property for session id."""
-        return self._session
-
-    @session.setter
-    def session(self, value):
-        self._session = value
-
-    def reset_session(self, session=None):
-        """
-        Reset session id.
-
-        :param str session: A unique session id (optional). If None, an id will
-            be generated using :py:func:`uuid.uuid4`.
-
-        :returns: New session id.
-        """
-        if session is None:
-            session = str(uuid.uuid4())
-        self._session = session
-        return self._session
-
-
-class GremlinResponse:
-    """Main interface for reading Gremlin Server responses. Typically returned
-    by ``GremlinClient.submit``, not created by user.
-
-    :param ``aiogremlin.response.GremlinClientWebSocketResponse`` ws: Websocket
-        connection.
-    :param str session: Session id (optional). Typically a uuid
-    :param loop: :ref:`event loop<asyncio-event-loop>` If param is ``None``,
-        `asyncio.get_event_loop` is used for getting default event loop
-        (optional)
-    """
-    def __init__(self, ws, *, session=None, loop=None, username="",
-                 password=""):
-        self._loop = loop or asyncio.get_event_loop()
-        self._session = session
-        self._stream = GremlinResponseStream(ws, username, password,
-                                             loop=self._loop)
-
-    @property
-    def stream(self):
-        """Read-only property used to get data from the stream in chunks.
-
-        :returns: :py:class:`aiogremlin.client.ResponseStream`"""
-        return self._stream
-
-    @property
-    def session(self):
-        """Session ID (if applicable)."""
-        return self._session
-
-    @asyncio.coroutine
-    def get(self):
-        """
-        :ref:`coroutine<coroutine>` method.
-
-        Get all messages from the stream.
-
-        :returns: :py:class:`list` :py:class:`aiogremlin.subprotocol.Message`
-        """
-        return (yield from self._run())
-
-    @asyncio.coroutine
-    def _run(self):
-        results = []
-        while True:
-            message = yield from self._stream.read()
-            if message is None:
-                break
-            results.append(message)
-        return results
-
-
-class GremlinResponseStream:
-    """
-    Encapsulate and read Gremlin Server responses. Typically instantiated by
-    GremlinResponse constructor, not by user.
-
-    :param ``aiogremlin.response.GremlinClientWebSocketResponse`` ws: Websocket
-        connection.
-    :param loop: :ref:`event loop<asyncio-event-loop>` If param is ``None``,
-        `asyncio.get_event_loop` is used for getting default event loop
-        (optional)
-    """
-    def __init__(self, ws, username, password, loop=None):
-        self._ws = ws
-        self._username = username
-        self._password = password
-        self._loop = loop or asyncio.get_event_loop()
-        data_stream = aiohttp.DataQueue(loop=self._loop)
-        self._stream = self._ws.parser.set_parser(gremlin_response_parser,
-                                                  output=data_stream)
-
-    @asyncio.coroutine
-    def read(self):
-        """
-        :ref:`coroutine<coroutine>` method
-
-        Read a message from the stream.
-
-        :returns: :py:class:`aiogremlin.subprotocol.Message`
-        """
-        if self._stream.at_eof():
-            yield from self._ws.release()
-            message = None
-        else:
-            asyncio.Task(self._ws.receive(), loop=self._loop)
-            try:
-                message = yield from self._stream.read()
-                if message.status_code == 407:
-                    writer = GremlinWriter(self._ws)
-                    writer.write(op="authentication", username=self._username,
-                                 password=self._password)
-                    asyncio.Task(self._ws.receive(), loop=self._loop)
-                    message = yield from self._stream.read()
-            except (RequestError, GremlinServerError):
-                yield from self._ws.release()
-                raise
-        return message
-
-
-@asyncio.coroutine
-def submit(gremlin, *,
-           url='http://localhost:8182/',
-           bindings=None,
-           lang="gremlin-groovy",
-           rebindings=None,
-           op="eval",
-           processor="",
-           timeout=None,
-           session=None,
-           loop=None,
-           conn_timeout=None,
-           username="",
-           password=""):
-    """
-    :ref:`coroutine<coroutine>`
-
-    Submit a script to the Gremlin Server.
-
-    :param str gremlin: The Gremlin script.
-    :param str url: url for Gremlin Server (optional). 'http://localhost:8182/'
-        by default
-    :param dict bindings: A mapping of bindings for Gremlin script.
-    :param str lang: Language of scripts submitted to the server.
-        "gremlin-groovy" by default
-    :param dict rebindings: Rebind ``Graph`` and ``TraversalSource``
-        objects to different variable names in the current request
-    :param str op: Gremlin Server op argument. "eval" by default.
-    :param str processor: Gremlin Server processor argument. "" by default.
-    :param float timeout: timeout for establishing connection (optional).
-        Values ``0`` or ``None`` mean no timeout
-    :param str session: Session id (optional). Typically a uuid
-    :param loop: :ref:`event loop<asyncio-event-loop>` If param is ``None``,
-        `asyncio.get_event_loop` is used for getting default event loop
-        (optional)
-    :param float conn_timeout: timeout for establishing connection (seconds)
-        (optional). Values ``0`` or ``None`` mean no timeout
-    :param username: Username for SASL auth
-    :param password: Password for SASL auth
-    :returns: :py:class:`aiogremlin.client.GremlinResponse` object
-    """
-
-    if loop is None:
-        loop = asyncio.get_event_loop()
-
-    connector = aiohttp.TCPConnector(force_close=True, loop=loop,
-                                     verify_ssl=False,
-                                     conn_timeout=conn_timeout)
-
-    client_session = aiohttp.ClientSession(
-        connector=connector, loop=loop,
-        ws_response_class=GremlinClientWebSocketResponse)
-
-    gremlin_client = GremlinClient(url=url, loop=loop,
-                                   ws_connector=client_session,
-                                   username=username, password=password)
-
-    try:
-        resp = yield from gremlin_client.submit(
-            gremlin, bindings=bindings, lang=lang, rebindings=rebindings,
-            op=op, processor=processor, session=session, timeout=timeout)
-
-        return resp
-
-    finally:
-        gremlin_client.detach()
-        client_session.detach()
diff --git a/aiogremlin/connector.py b/aiogremlin/connector.py
deleted file mode 100644
index f3eae44c5ab613ab0797d84e7b0067b3680f7783..0000000000000000000000000000000000000000
--- a/aiogremlin/connector.py
+++ /dev/null
@@ -1,33 +0,0 @@
-"""Websocket connection factory and manager."""
-
-import asyncio
-
-from aiowebsocketclient import WebSocketConnector
-
-from aiogremlin.response import GremlinClientWebSocketResponse
-
-__all__ = ("GremlinConnector",)
-
-
-class GremlinConnector(WebSocketConnector):
-    """Create and manage reusable websocket connections. Out of the box
-    support for multiple enpoints (databases).
-
-    :param float conn_timeout: timeout for establishing connection (seconds)
-        (optional). Values ``0`` or ``None`` mean no timeout
-    :param bool force_close: close websockets after release
-    :param int limit: limit for total open websocket connections
-    :param aiohttp.client.ClientSession client_session: Underlying HTTP
-        session used to establish websocket connections
-    :param loop: `event loop` If param is ``None``, `asyncio.get_event_loop`
-        is used for getting default event loop (optional)
-    :param ws_response_class: WebSocketResponse class implementation.
-        ``ClientWebSocketResponse`` by default
-    :param bool verbose: Set log level to info. False by default
-    """
-    def __init__(self, *, conn_timeout=None, force_close=False, limit=1024,
-                 client_session=None, loop=None, verbose=False):
-
-        super().__init__(conn_timeout=conn_timeout, force_close=force_close,
-                         limit=limit, client_session=client_session, loop=loop,
-                         ws_response_class=GremlinClientWebSocketResponse)
diff --git a/aiogremlin/driver/__init__.py b/aiogremlin/driver/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4861b633fc5f4293603229f4cab9d3282df4c4a1
--- /dev/null
+++ b/aiogremlin/driver/__init__.py
@@ -0,0 +1,7 @@
+from aiogremlin.driver import provider
+from aiogremlin.driver.client import Client
+from aiogremlin.driver.cluster import Cluster
+from aiogremlin.driver.connection import Connection
+from aiogremlin.driver.pool import ConnectionPool
+from aiogremlin.driver.protocol import GremlinServerWSProtocol
+from aiogremlin.driver.server import GremlinServer
diff --git a/aiogremlin/driver/aiohttp/__init__.py b/aiogremlin/driver/aiohttp/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/aiogremlin/driver/aiohttp/transport.py b/aiogremlin/driver/aiohttp/transport.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c15013ed8c7270e901c2dbea76b4cba12a95b8d
--- /dev/null
+++ b/aiogremlin/driver/aiohttp/transport.py
@@ -0,0 +1,36 @@
+import aiohttp
+
+from aiogremlin.gremlin_python.driver import transport
+
+
+class AiohttpTransport(transport.AbstractBaseTransport):
+
+    def __init__(self, loop):
+        self._loop = loop
+        self._connected = False
+
+    async def connect(self, url, *, ssl_context=None):
+        await self.close()
+        connector = aiohttp.TCPConnector(
+            ssl_context=ssl_context, loop=self._loop)
+        self._client_session = aiohttp.ClientSession(
+            loop=self._loop, connector=connector)
+        self._ws = await self._client_session.ws_connect(url)
+        self._connected = True
+
+    def write(self, message):
+        self._ws.send_bytes(message)
+
+    async def read(self):
+        return await self._ws.receive()
+
+    async def close(self):
+        if self._connected:
+            if not self._ws.closed:
+                await self._ws.close()
+            if not self._client_session.closed:
+                await self._client_session.close()
+
+    @property
+    def closed(self):
+        return self._ws.closed or self._client_session.closed
diff --git a/aiogremlin/driver/client.py b/aiogremlin/driver/client.py
new file mode 100644
index 0000000000000000000000000000000000000000..6bd597fe16108b4bac1bdbbda392b2b0716f6ead
--- /dev/null
+++ b/aiogremlin/driver/client.py
@@ -0,0 +1,81 @@
+"""Client for the Tinkerpop 3 Gremlin Server."""
+
+from aiogremlin import exception
+from aiogremlin.gremlin_python.driver import request
+from aiogremlin.gremlin_python.process import traversal
+
+
+class Client:
+    """
+    Client that utilizes a :py:class:`Cluster<aiogremlin.cluster.Cluster>`
+    to access a cluster of Gremlin Server hosts. Issues requests to hosts using
+    a round robin strategy.
+
+    :param aiogremlin.cluster.Cluster cluster: Cluster used by
+        client
+    :param asyncio.BaseEventLoop loop:
+    """
+    def __init__(self, cluster, loop, *, aliases=None, processor=None,
+                 op=None):
+        self._cluster = cluster
+        self._loop = loop
+        if aliases is None:
+            aliases = {}
+        self._aliases = aliases
+        if processor is None:
+            processor = ''
+        self._processor = processor
+        if op is None:
+            op = 'eval'
+        self._op = op
+
+    @property
+    def aliases(self):
+        return self._aliases
+
+    @property
+    def message_serializer(self):
+        return self.cluster.config['message_serializer']
+
+    @property
+    def cluster(self):
+        """
+        Readonly property.
+
+        :returns: The instance of
+            :py:class:`Cluster<aiogremlin.driver.cluster.Cluster>` associated with
+            client.
+        """
+        return self._cluster
+
+    async def close(self):
+        await self._cluster.close()
+
+    def alias(self, aliases):
+        client = Client(self._cluster, self._loop,
+                        aliases=aliases)
+        return client
+
+    async def submit(self, message, bindings=None):
+        """
+        **coroutine** Submit a script and bindings to the Gremlin Server.
+
+        :returns: :py:class:`ResultSet<aiogremlin.driver.resultset.ResultSet>`
+            object
+        """
+        if isinstance(message, traversal.Bytecode):
+            message = request.RequestMessage(
+                processor='traversal', op='bytecode',
+                args={'gremlin': message,
+                      'aliases': self._aliases})
+        elif isinstance(message, str):
+            message = request.RequestMessage(
+                processor='', op='eval',
+                args={'gremlin': message,
+                      'aliases': self._aliases})
+            if bindings:
+                message.args.update({'bindings': bindings})
+        conn = await self.cluster.get_connection()
+        resp = await conn.write(message)
+        self._loop.create_task(conn.release_task(resp))
+        return resp
diff --git a/aiogremlin/driver/cluster.py b/aiogremlin/driver/cluster.py
new file mode 100644
index 0000000000000000000000000000000000000000..abaa8af7c6d639ca257feecdac29a02c430f357d
--- /dev/null
+++ b/aiogremlin/driver/cluster.py
@@ -0,0 +1,199 @@
+import asyncio
+import collections
+import configparser
+import importlib
+import ssl
+
+try:
+    import ujson as json
+except ImportError:
+    import json
+
+import yaml
+
+from aiogremlin import exception
+from aiogremlin import driver
+from aiogremlin.gremlin_python.driver import serializer
+
+
+def my_import(name):
+    names = name.rsplit('.', maxsplit=1)
+    if len(names) != 2:
+        raise exception.ConfigError("not a valid absolute python path to a class: {}".format(name))
+    module_name, class_name = names
+    try:
+        module = importlib.import_module(module_name)
+    except ImportError:
+        raise exception.ConfigError(
+                "Error processing cluster configuration: could not import {}".format(name))
+    return getattr(module, class_name)
+
+
+class Cluster:
+    """
+    A cluster of Gremlin Server hosts. This object provides the main high
+    level interface used by the :py:mod:`aiogremlin` module.
+
+    :param asyncio.BaseEventLoop loop:
+    """
+
+    DEFAULT_CONFIG = {
+        'scheme': 'ws',
+        'hosts': ['localhost'],
+        'port': 8182,
+        'ssl_certfile': '',
+        'ssl_keyfile': '',
+        'ssl_password': '',
+        'username': '',
+        'password': '',
+        'response_timeout': None,
+        'max_conns': 4,
+        'min_conns': 1,
+        'max_times_acquired': 16,
+        'max_inflight': 64,
+        'message_serializer': 'aiogremlin.gremlin_python.driver.serializer.GraphSONMessageSerializer',
+        'provider': 'aiogremlin.driver.provider.TinkerGraph'
+    }
+
+    def __init__(self, loop, aliases=None, **config):
+        self._loop = loop
+        default_config = dict(self.DEFAULT_CONFIG)
+        default_config.update(config)
+        self._config = self._process_config_imports(default_config)
+        self._hosts = collections.deque()
+        self._closed = False
+        if aliases is None:
+            aliases = {}
+        self._aliases = aliases
+
+    @classmethod
+    async def open(cls, loop, *, aliases=None, configfile=None, **config):
+        """
+        **coroutine** Open a cluster, connecting to all available hosts as
+        specified in configuration.
+
+        :param asyncio.BaseEventLoop loop:
+        :param str configfile: Optional configuration file in .json or
+            .yml format
+        """
+        cluster = cls(loop, aliases=aliases, **config)
+        if configfile:
+            cluster.config_from_file(configfile)
+        await cluster.establish_hosts()
+        return cluster
+
+    @property
+    def hosts(self):
+        return self._hosts
+
+    @property
+    def config(self):
+        """
+        Readonly property.
+
+        :returns: `dict` containing the cluster configuration
+        """
+        return self._config
+
+    async def get_connection(self):
+        """
+        **coroutine** Get connection from next available host in a round robin
+        fashion.
+
+        :returns: :py:class:`Connection<aiogremlin.connection.Connection>`
+        """
+        if not self._hosts:
+            await self.establish_hosts()
+        host = self._hosts.popleft()
+        conn = await host.get_connection()
+        self._hosts.append(host)
+        return conn
+
+    async def establish_hosts(self):
+        """
+        **coroutine** Connect to all hosts as specified in configuration.
+        """
+        scheme = self._config['scheme']
+        hosts = self._config['hosts']
+        port = self._config['port']
+        for host in hosts:
+            url = '{}://{}:{}/gremlin'.format(scheme, host, port)
+            host = await driver.GremlinServer.open(
+                url, self._loop, **dict(self._config))
+            self._hosts.append(host)
+
+    def config_from_file(self, filename):
+        """
+        Load configuration from from file.
+
+        :param str filename: Path to the configuration file.
+        """
+        if filename.endswith('yml') or filename.endswith('yaml'):
+            self.config_from_yaml(filename)
+        elif filename.endswith('.json'):
+            self.config_from_json(filename)
+        else:
+            raise exception.ConfigurationError('Unknown config file format')
+
+    def config_from_yaml(self, filename):
+        with open(filename, 'r') as f:
+            config = yaml.load(f)
+        config = self._process_config_imports(config)
+        self._config.update(config)
+
+    def config_from_json(self, filename):
+        """
+        Load configuration from from JSON file.
+
+        :param str filename: Path to the configuration file.
+        """
+        with open(filename, 'r') as f:
+            config = json.load(f)
+        config = self._process_config_imports(config)
+        self.config.update(config)
+
+    def _process_config_imports(self, config):
+        message_serializer = config.get('message_serializer')
+        provider = config.get('provider')
+        if isinstance(message_serializer, str):
+            config['message_serializer'] = my_import(message_serializer)
+        if isinstance(provider, str):
+            config['provider'] = my_import(provider)
+        return config
+
+    def config_from_module(self, module):
+        if isinstance(module, str):
+            module = importlib.import_module(module)
+        config = dict()
+        for item in dir(module):
+            if not item.startswith('_') and item.lower() in self.DEFAULT_CONFIG:
+                config[item.lower()] = getattr(module, item)
+        config = self._process_config_imports(config)
+        self.config.update(config)
+
+    async def connect(self, aliases=None):
+        """
+        **coroutine** Get a connected client. Main API method.
+
+        :returns: A connected instance of `Client<aiogremlin.client.Client>`
+        """
+        aliases = aliases or self._aliases
+        if not self._hosts:
+            await self.establish_hosts()
+        # if session:
+        #     host = self._hosts.popleft()
+        #     client = client.SessionedClient(host, self._loop, session,
+        #                                     aliases=aliases)
+        #     self._hosts.append(host)
+        # else:
+        client = driver.Client(self, self._loop, aliases=aliases)
+        return client
+
+    async def close(self):
+        """**coroutine** Close cluster and all connected hosts."""
+        waiters = []
+        while self._hosts:
+            host = self._hosts.popleft()
+            waiters.append(host.close())
+        await asyncio.gather(*waiters, loop=self._loop)
+        self._closed = True
diff --git a/aiogremlin/driver/connection.py b/aiogremlin/driver/connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..ceab16ea6d54f24dab5fd1d8ec585b4bf2423a6c
--- /dev/null
+++ b/aiogremlin/driver/connection.py
@@ -0,0 +1,166 @@
+import abc
+import asyncio
+import base64
+import collections
+import logging
+import uuid
+
+import aiohttp
+
+try:
+    import ujson as json
+except ImportError:
+    import json
+
+from aiogremlin.driver import provider, resultset
+from aiogremlin.driver.protocol import GremlinServerWSProtocol
+from aiogremlin.driver.aiohttp.transport import AiohttpTransport
+from aiogremlin.gremlin_python.driver import serializer
+
+
+logger = logging.getLogger(__name__)
+
+
+class Connection:
+    """
+    Main classd for interacting with the Gremlin Server. Encapsulates a
+    websocket connection. Not instantiated directly. Instead use
+    :py:meth:`Connection.open<aiogremlin.connection.Connection.open>`.
+
+    :param str url: url for host Gremlin Server
+    :param aiohttp.ClientWebSocketResponse ws: open websocket connection
+    :param asyncio.BaseEventLoop loop:
+    :param aiohttp.ClientSession: Client session used to establish websocket
+        connections
+    :param float response_timeout: (optional) `None` by default
+    :param str username: Username for database auth
+    :param str password: Password for database auth
+    :param int max_inflight: Maximum number of unprocessed requests at any
+        one time on the connection
+    """
+    def __init__(self, url, transport, protocol, loop, username, password,
+                 max_inflight, response_timeout, message_serializer, provider):
+        self._url = url
+        self._transport = transport
+        self._protocol = protocol
+        self._loop = loop
+        self._response_timeout = response_timeout
+        self._username = username
+        self._password = password
+        self._closed = False
+        self._result_sets = {}
+        self._receive_task = self._loop.create_task(self._receive())
+        self._semaphore = asyncio.Semaphore(value=max_inflight,
+                                            loop=self._loop)
+        if isinstance(message_serializer, type):
+            message_serializer = message_serializer()
+        self._message_serializer = message_serializer
+        self._provider = provider
+
+    @classmethod
+    async def open(cls, url, loop, *,
+                   protocol=None,
+                   transport_factory=None,
+                   ssl_context=None,
+                   username='',
+                   password='',
+                   max_inflight=64,
+                   response_timeout=None,
+                   message_serializer=serializer.GraphSONMessageSerializer,
+                   provider=provider.TinkerGraph):
+        """
+        **coroutine** Open a connection to the Gremlin Server.
+
+        :param str url: url for host Gremlin Server
+        :param asyncio.BaseEventLoop loop:
+        :param ssl.SSLContext ssl_context:
+        :param str username: Username for database auth
+        :param str password: Password for database auth
+
+        :param int max_inflight: Maximum number of unprocessed requests at any
+            one time on the connection
+        :param float response_timeout: (optional) `None` by default
+
+        :returns: :py:class:`Connection<aiogremlin.connection.Connection>`
+        """
+        if not protocol:
+            protocol = GremlinServerWSProtocol(message_serializer)
+        if not transport_factory:
+            transport_factory = lambda: AiohttpTransport(loop)
+        transport = transport_factory()
+        await transport.connect(url, ssl_context=ssl_context)
+        return cls(url, transport, protocol, loop, username, password,
+                   max_inflight, response_timeout, message_serializer,
+                   provider)
+
+    @property
+    def message_serializer(self):
+        return self._message_serializer
+
+    @property
+    def closed(self):
+        """
+        Check if connection has been closed.
+
+        :returns: `bool`
+        """
+        return self._closed or self._transport.closed
+
+    @property
+    def url(self):
+        """
+        Readonly property.
+
+        :returns: str The url association with this connection.
+        """
+        return self._url
+
+    async def write(self, message):
+        """
+        Submit a script and bindings to the Gremlin Server
+
+        :param str processor: Gremlin Server processor argument
+        :param str op: Gremlin Server op argument
+        :param args: Keyword arguments for Gremlin Server. Depend on processor
+            and op.
+        :returns: :py:class:`ResultSet<aiogremlin.driver.resultset.ResultSet>`
+            object
+        """
+        await self._semaphore.acquire()
+        request_id = str(uuid.uuid4())
+        message = self._message_serializer.serialize_message(
+            request_id, message)
+        if self._transport.closed:
+            await self._transport.connect(self.url)
+        self._transport.write(message)
+        result_set = resultset.ResultSet(request_id, self._response_timeout,
+                                   self._loop)
+        self._result_sets[request_id] = result_set
+        self._loop.create_task(
+            self._terminate_response(result_set, request_id))
+        return result_set
+
+    submit = write
+
+    async def close(self):
+        """**coroutine** Close underlying connection and mark as closed."""
+        self._receive_task.cancel()
+        await self._transport.close()
+        self._closed = True
+
+    async def _terminate_response(self, resp, request_id):
+        await resp.done.wait()
+        del self._result_sets[request_id]
+        self._semaphore.release()
+
+    async def _receive(self):
+        while True:
+            data = await self._transport.read()
+            await self._protocol.data_received(data, self._result_sets)
+
+    async def __aenter__(self):
+        return self
+
+    async def __aexit__(self, exc_type, exc, tb):
+        await self.close()
+        self._conn = None
diff --git a/aiogremlin/driver/pool.py b/aiogremlin/driver/pool.py
new file mode 100644
index 0000000000000000000000000000000000000000..32d74721ede6f81262807c9437ae6c6e9af1bb93
--- /dev/null
+++ b/aiogremlin/driver/pool.py
@@ -0,0 +1,202 @@
+import asyncio
+import collections
+
+import aiohttp
+
+from aiogremlin.driver import connection
+
+
+class PooledConnection:
+    """
+    Wrapper for :py:class:`Connection<aiogremlin.connection.Connection>`
+    that helps manage tomfoolery associated with connection pooling.
+
+    :param aiogremlin.connection.Connection conn:
+    :param aiogremlin.pool.ConnectionPool pool:
+    """
+    def __init__(self, conn, pool):
+        self._conn = conn
+        self._pool = pool
+        self._times_acquired = 0
+
+    @property
+    def times_acquired(self):
+        """
+        Readonly property.
+
+        :returns: int
+        """
+        return self._times_acquired
+
+    def increment_acquired(self):
+        """Increment times acquired attribute by 1"""
+        self._times_acquired += 1
+
+    def decrement_acquired(self):
+        """Decrement times acquired attribute by 1"""
+        self._times_acquired -= 1
+
+    async def write(self, message):
+        """
+        **coroutine** Submit a script and bindings to the Gremlin Server
+
+        :param str processor: Gremlin Server processor argument
+        :param str op: Gremlin Server op argument
+        :param args: Keyword arguments for Gremlin Server. Depend on processor
+            and op.
+
+        :returns: :py:class:`Response` object
+        """
+        return await self._conn.write(message)
+
+    submit = write
+
+    async def release_task(self, resp):
+        await resp.done.wait()
+        self.release()
+
+    def release(self):
+        self._pool.release(self)
+
+    async def close(self):
+        """Close underlying connection"""
+        await self._conn.close()
+        self._conn = None
+        self._pool = None
+
+    @property
+    def closed(self):
+        """
+        Readonly property.
+
+        :returns: bool
+        """
+        return self._conn.closed
+
+
+class ConnectionPool:
+    """
+    A pool of connections to a Gremlin Server host.
+
+    :param str url: url for host Gremlin Server
+    :param asyncio.BaseEventLoop loop:
+    :param ssl.SSLContext ssl_context:
+    :param str username: Username for database auth
+    :param str password: Password for database auth
+    :param float response_timeout: (optional) `None` by default
+    :param int max_conns: Maximum number of conns to a host
+    :param int min_connsd: Minimum number of conns to a host
+    :param int max_times_acquired: Maximum number of times a conn can be
+        shared by multiple coroutines (clients)
+    :param int max_inflight: Maximum number of unprocessed requests at any
+        one time on the connection
+    """
+
+    def __init__(self, url, loop, ssl_context, username, password, max_conns,
+                 min_conns, max_times_acquired, max_inflight, response_timeout,
+                 message_serializer, provider):
+        self._url = url
+        self._loop = loop
+        self._ssl_context = ssl_context
+        self._username = username
+        self._password = password
+        self._max_conns = max_conns
+        self._min_conns = min_conns
+        self._max_times_acquired = max_times_acquired
+        self._max_inflight = max_inflight
+        self._response_timeout = response_timeout
+        self._message_serializer = message_serializer
+        self._condition = asyncio.Condition(loop=self._loop)
+        self._available = collections.deque()
+        self._acquired = collections.deque()
+        self._provider = provider
+
+    @property
+    def url(self):
+        """
+        Readonly property.
+
+        :returns: str
+        """
+        return self._url
+
+    async def init_pool(self):
+        """**coroutine** Open minumum number of connections to host"""
+        for i in range(self._min_conns):
+            conn = await self._get_connection(self._username,
+                                              self._password,
+                                              self._max_inflight,
+                                              self._response_timeout,
+                                              self._message_serializer,
+                                              self._provider)
+            self._available.append(conn)
+
+    def release(self, conn):
+        """
+        Release connection back to pool after use.
+
+        :param PooledConnection conn:
+        """
+        if conn.closed:
+            self._acquired.remove(conn)
+        else:
+            conn.decrement_acquired()
+            if not conn.times_acquired:
+                self._acquired.remove(conn)
+                self._available.append(conn)
+        self._loop.create_task(self._notify())
+
+    async def _notify(self):
+        async with self._condition:
+            self._condition.notify()
+
+    async def acquire(self):
+        """**coroutine** Acquire a new connection from the pool."""
+        async with self._condition:
+            while True:
+                while self._available:
+                    conn = self._available.popleft()
+                    if not conn.closed:
+                        conn.increment_acquired()
+                        self._acquired.append(conn)
+                        return conn
+                if len(self._acquired) < self._max_conns:
+                    conn = await self._get_connection(self._username, self._password,
+                                                      self._max_inflight,
+                                                      self._response_timeout,
+                                                      self._message_serializer,
+                                                      self._provider)
+                    conn.increment_acquired()
+                    self._acquired.append(conn)
+                    return conn
+                else:
+                    for x in range(len(self._acquired)):
+                        conn = self._acquired.popleft()
+                        if conn.times_acquired < self._max_times_acquired:
+                            conn.increment_acquired()
+                            self._acquired.append(conn)
+                            return conn
+                        self._acquired.append(conn)
+                    else:
+                        await self._condition.wait()
+
+    async def close(self):
+        """**coroutine** Close connection pool."""
+        waiters = []
+        while self._available:
+            conn = self._available.popleft()
+            waiters.append(conn.close())
+        while self._acquired:
+            conn = self._acquired.popleft()
+            waiters.append(conn.close())
+        await asyncio.gather(*waiters, loop=self._loop)
+
+    async def _get_connection(self, username, password, max_inflight,
+                              response_timeout, message_serializer, provider):
+        conn = await connection.Connection.open(
+            self._url, self._loop, ssl_context=self._ssl_context,
+            username=username, password=password,
+            response_timeout=response_timeout,
+            message_serializer=message_serializer, provider=provider)
+        conn = PooledConnection(conn, self)
+        return conn
diff --git a/aiogremlin/driver/protocol.py b/aiogremlin/driver/protocol.py
new file mode 100644
index 0000000000000000000000000000000000000000..03d189c127f9a8cc068cab98f98c9e0d61513e41
--- /dev/null
+++ b/aiogremlin/driver/protocol.py
@@ -0,0 +1,87 @@
+import base64
+import collections
+import logging
+
+import aiohttp
+
+try:
+    import ujson as json
+except ImportError:
+    import json
+
+from aiogremlin.gremlin_python.driver import protocol, request, serializer
+
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+logger = logging.getLogger(__name__)
+
+
+Message = collections.namedtuple(
+    "Message",
+    ["status_code", "data", "message"])
+
+
+class GremlinServerWSProtocol(protocol.AbstractBaseProtocol):
+
+    def __init__(self, message_serializer, username='', password=''):
+        if isinstance(message_serializer, type):
+            message_serializer = message_serializer()
+        self._message_serializer = message_serializer
+        self._username = username
+        self._password = password
+
+    def connection_made(self, transport):
+        self._transport = transport
+
+    def write(self, request_id, request_message):
+        message = self._message_serializer.serialize_message(
+            request_id, request_message)
+        self._transport.write(message)
+
+    async def data_received(self, data, results_dict):
+        if data.tp == aiohttp.MsgType.close:
+            await self._transport.close()
+        elif data.tp == aiohttp.MsgType.error:
+            # This won't raise properly, fix
+            raise data.data
+        elif data.tp == aiohttp.MsgType.closed:
+            # Hmm
+            pass
+        else:
+            if data.tp == aiohttp.MsgType.binary:
+                data = data.data.decode()
+            elif data.tp == aiohttp.MsgType.text:
+                data = data.data.strip()
+            message = json.loads(data)
+            request_id = message['requestId']
+            status_code = message['status']['code']
+            data = message['result']['data']
+            msg = message['status']['message']
+            if request_id in results_dict:
+                result_set = results_dict[request_id]
+                aggregate_to = message['result']['meta'].get('aggregateTo',
+                                                             'list')
+                result_set.aggregate_to = aggregate_to
+                if status_code == 407:
+                    auth = b''.join([b'\x00', self._username.encode('utf-8'),
+                                     b'\x00', self._password.encode('utf-8')])
+                    request_message = request.RequestMessage(
+                        'traversal', 'authentication',
+                        {'sasl': base64.b64encode(auth).decode()})
+                    self.write(request_id, request_message)
+                elif status_code == 204:
+                    result_set.queue_result(None)
+                else:
+                    if data:
+                        for result in data:
+                            result = self._message_serializer.deserialize_message(result)
+                            message = Message(status_code, result, msg)
+                            result_set.queue_result(message)
+                    else:
+                        data = self._message_serializer.deserialize_message(data)
+                        message = Message(status_code, data, msg)
+                        result_set.queue_result(message)
+                    if status_code != 206:
+                        result_set.queue_result(None)
diff --git a/aiogremlin/driver/provider.py b/aiogremlin/driver/provider.py
new file mode 100644
index 0000000000000000000000000000000000000000..5325612d1518338332caf9c1462db142a9e3aca4
--- /dev/null
+++ b/aiogremlin/driver/provider.py
@@ -0,0 +1,14 @@
+class Provider:
+    """Superclass for provider plugins"""
+    DEFAULT_OP_ARGS = {}
+
+    @classmethod
+    def get_default_op_args(cls, processor):
+        return cls.DEFAULT_OP_ARGS.get(processor, dict())
+
+
+class TinkerGraph(Provider):  # TODO
+    """Default provider"""
+    @staticmethod
+    def get_hashable_id(val):
+        return val
diff --git a/aiogremlin/driver/resultset.py b/aiogremlin/driver/resultset.py
new file mode 100644
index 0000000000000000000000000000000000000000..a53765d28f3682e6e9b3d97bf84a5925357e28b5
--- /dev/null
+++ b/aiogremlin/driver/resultset.py
@@ -0,0 +1,98 @@
+import asyncio
+import functools
+
+from aiogremlin import exception
+
+
+def error_handler(fn):
+    @functools.wraps(fn)
+    async def wrapper(self):
+        msg = await fn(self)
+        if msg:
+            if msg.status_code not in [200, 206]:
+                self.close()
+                raise exception.GremlinServerError(
+                    "{0}: {1}".format(msg.status_code, msg.message))
+            msg = msg.data
+        return msg
+    return wrapper
+
+
+class ResultSet:
+    """Gremlin Server response implementated as an async iterator."""
+    def __init__(self, request_id, timeout, loop):
+        self._response_queue = asyncio.Queue(loop=loop)
+        self._request_id = request_id
+        self._loop = loop
+        self._timeout = timeout
+        self._done = asyncio.Event(loop=self._loop)
+        self._aggregate_to = None
+
+    @property
+    def request_id(self):
+        return self._request_id
+
+    @property
+    def stream(self):
+        return self._response_queue
+
+    def queue_result(self, result):
+        if result is None:
+            self.done.set()
+        self._response_queue.put_nowait(result)
+
+    @property
+    def done(self):
+        """
+        Readonly property.
+
+        :returns: `asyncio.Event` object
+        """
+        return self._done
+
+    @property
+    def aggregate_to(self):
+        return self._aggregate_to
+
+    @aggregate_to.setter
+    def aggregate_to(self, val):
+        self._aggregate_to = val
+
+    async def __aiter__(self):
+        return self
+
+    async def __anext__(self):
+        msg = await self.one()
+        if not msg:
+            raise StopAsyncIteration
+        return msg
+
+    def close(self):
+        """Close response stream by setting done flag to true."""
+        self.done.set()
+        self._loop = None
+        self._response_queue = None
+
+    @error_handler
+    async def one(self):
+        """Get a single message from the response stream"""
+        if not self._response_queue.empty():
+            msg = self._response_queue.get_nowait()
+        elif self.done.is_set():
+            self.close()
+            msg = None
+        else:
+            try:
+                msg = await asyncio.wait_for(self._response_queue.get(),
+                                             timeout=self._timeout,
+                                             loop=self._loop)
+            except asyncio.TimeoutError:
+                self.close()
+                raise exception.ResponseTimeoutError('Response timed out')
+        return msg
+
+    async def all(self):
+        results = []
+        async for result in self:
+            results.append(result)
+        return results
diff --git a/aiogremlin/driver/server.py b/aiogremlin/driver/server.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e392fe73948f740211aa4fe88154299aa3c0ad0
--- /dev/null
+++ b/aiogremlin/driver/server.py
@@ -0,0 +1,97 @@
+from aiogremlin.driver import pool
+
+
+class GremlinServer:
+    """
+    Class that wraps a connection pool. Currently doesn't do much, but may
+    be useful in the future....
+
+    :param pool.ConnectionPool pool:
+    """
+
+    def __init__(self, url, loop, **config):
+        self._pool = None
+        self._url = url
+        self._loop = loop
+        self._response_timeout = config['response_timeout']
+        self._username = config['username']
+        self._password = config['password']
+        self._max_times_acquired = config['max_times_acquired']
+        self._max_conns = config['max_conns']
+        self._min_conns = config['min_conns']
+        self._max_inflight = config['max_inflight']
+        self._message_serializer = config['message_serializer']
+        self._provider = config['provider']
+        scheme = config['scheme']
+        if scheme in ['https', 'wss']:
+            certfile = config['ssl_certfile']
+            keyfile = config['ssl_keyfile']
+            ssl_password = config['ssl_password']
+            ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+            ssl_context.load_cert_chain(
+                certfile, keyfile=keyfile, password=ssl_password)
+            self._ssl_context = ssl_context
+        else:
+            self._ssl_context = None
+
+    @property
+    def url(self):
+        return self._url
+
+    @property
+    def pool(self):
+        """
+        Readonly property.
+
+        :returns: :py:class:`ConnectionPool<goblin.driver.pool.ConnectionPool>`
+        """
+        if self._pool:
+            return self._pool
+
+    async def close(self):
+        """**coroutine** Close underlying connection pool."""
+        if self._pool:
+            await self._pool.close()
+            self._pool = None
+
+    async def get_connection(self):
+        """**coroutine** Acquire a connection from the pool."""
+        try:
+            conn = await self._pool.acquire()
+        except AttributeError:
+            raise Exception("Please initialize pool")
+        return conn
+
+    async def initialize(self):
+        conn_pool = pool.ConnectionPool(
+            self._url, self._loop, self._ssl_context, self._username,
+            self._password, self._max_conns, self._min_conns,
+            self._max_times_acquired, self._max_inflight,
+            self._response_timeout, self._message_serializer, self._provider)
+        await conn_pool.init_pool()
+        self._pool = conn_pool
+
+    @classmethod
+    async def open(cls, url, loop, **config):
+        """
+        **coroutine** Establish connection pool and host to Gremlin Server.
+
+        :param str url: url for host Gremlin Server
+        :param asyncio.BaseEventLoop loop:
+        :param ssl.SSLContext ssl_context:
+        :param str username: Username for database auth
+        :param str password: Password for database auth
+        :param float response_timeout: (optional) `None` by default
+        :param int max_conns: Maximum number of conns to a host
+        :param int min_connsd: Minimum number of conns to a host
+        :param int max_times_acquired: Maximum number of times a conn can be
+            shared by multiple coroutines (clients)
+        :param int max_inflight: Maximum number of unprocessed requests at any
+            one time on the connection
+
+        :returns: :py:class:`GremlinServer`
+        """
+
+        host = cls(url, loop, **config)
+        await host.initialize()
+        return host
diff --git a/aiogremlin/exception.py b/aiogremlin/exception.py
new file mode 100644
index 0000000000000000000000000000000000000000..51f0ea5967de894e2e8fd6e64c936d37cd6bf17b
--- /dev/null
+++ b/aiogremlin/exception.py
@@ -0,0 +1,30 @@
+class ConfigError(Exception):
+    pass
+
+
+class ClientError(Exception):
+    pass
+
+
+class MappingError(Exception):
+    pass
+
+
+class ValidationError(Exception):
+    pass
+
+
+class ElementError(Exception):
+    pass
+
+
+class ConfigurationError(Exception):
+    pass
+
+
+class GremlinServerError(Exception):
+    pass
+
+
+class ResponseTimeoutError(Exception):
+    pass
diff --git a/aiogremlin/exceptions.py b/aiogremlin/exceptions.py
deleted file mode 100644
index 890932a5cf11f87340c4ca99f6f506b941be99a1..0000000000000000000000000000000000000000
--- a/aiogremlin/exceptions.py
+++ /dev/null
@@ -1,64 +0,0 @@
-"""Gremlin Server exceptions."""
-
-__all__ = ("RequestError", "GremlinServerError")
-
-
-class StatusException(IOError):
-
-    def __init__(self, value, result):
-        """Handle all exceptions returned from the Gremlin Server.
-        """
-        self.value = value
-        self.response = {
-            401: ("UNAUTHORIZED", ("The request attempted to access resources " +
-                  "that the requesting user did not have access to")),
-            498: ("MALFORMED_REQUEST",
-                  ("The request message was not properly formatted which " +
-                   "means it could not be parsed at all or the 'op' code " +
-                   "was not recognized such that Gremlin Server could " +
-                   "properly route it for processing. Check the message " +
-                   "format and retry the request")),
-            499: ("INVALID_REQUEST_ARGUMENTS",
-                  ("The request message was parseable, but the arguments " +
-                   "supplied in the message were in conflict or incomplete. " +
-                   "Check the message format and retry the request.")),
-            500: ("SERVER_ERROR",
-                  ("A general server error occurred that prevented the " +
-                   "request from being processed.")),
-            596: ("TRAVERSAL_EVALUATION",
-                  ("The remote " +
-                   "{@link org.apache.tinkerpop.gremlin.process.Traversal} " +
-                   "submitted for processing evaluated in on the server " +
-                   "with errors and could not be processed")),
-            597: ("SCRIPT_EVALUATION",
-                  ("The script submitted for processing evaluated in the " +
-                   "{@code ScriptEngine} with errors and could not be  " +
-                   "processed.Check the script submitted for syntax errors " +
-                   "or other problems and then resubmit.")),
-            598: ("TIMEOUT",
-                  ("The server exceeded one of the timeout settings for the " +
-                   "request and could therefore only partially respond or " +
-                   " not respond at all.")),
-            599: ("SERIALIZATION",
-                  ("The server was not capable of serializing an object " +
-                   "that was returned from the script supplied on the " +
-                   "requst. Either transform the object into something " +
-                   "Gremlin Server can process within the script or install " +
-                   "mapper serialization classes to Gremlin Server."))
-        }
-        if result:
-            result = "\n\n{}".format(result)
-        self.message = 'Code [{}]: {}. {}.{}'.format(
-            self.value,
-            self.response[self.value][0],
-            self.response[self.value][1],
-            result)
-        super().__init__(self.message)
-
-
-class RequestError(StatusException):
-    pass
-
-
-class GremlinServerError(StatusException):
-    pass
diff --git a/aiogremlin/gremlin_python/__init__.py b/aiogremlin/gremlin_python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7626550738f12ccd5e18b8c06a8d68aaab882066
--- /dev/null
+++ b/aiogremlin/gremlin_python/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/aiogremlin/gremlin_python/driver/__init__.py b/aiogremlin/gremlin_python/driver/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7626550738f12ccd5e18b8c06a8d68aaab882066
--- /dev/null
+++ b/aiogremlin/gremlin_python/driver/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/aiogremlin/gremlin_python/driver/protocol.py b/aiogremlin/gremlin_python/driver/protocol.py
new file mode 100644
index 0000000000000000000000000000000000000000..af88ba8eda170a5e3982f7add2ebe392af89d4ec
--- /dev/null
+++ b/aiogremlin/gremlin_python/driver/protocol.py
@@ -0,0 +1,45 @@
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 abc
+import base64
+import collections
+import uuid
+
+try:
+    import ujson as json
+except ImportError:
+    import json
+
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class AbstractBaseProtocol(metaclass=abc.ABCMeta):
+
+    @abc.abstractmethod
+    def connection_made(self, transport):
+        self._transport = transport
+
+    @abc.abstractmethod
+    def data_received(self, message):
+        pass
+
+    @abc.abstractmethod
+    def write(self, request_id, request_message):
+        pass
diff --git a/aiogremlin/gremlin_python/driver/remote_connection.py b/aiogremlin/gremlin_python/driver/remote_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..4101a8c7b1340e69c743c2d05e56b57c11f1d44d
--- /dev/null
+++ b/aiogremlin/gremlin_python/driver/remote_connection.py
@@ -0,0 +1,75 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+import abc
+import collections
+
+from aiogremlin.gremlin_python.driver import request
+from aiogremlin.gremlin_python.process import traversal
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+
+class RemoteConnection(metaclass=abc.ABCMeta):
+    def __init__(self, url, traversal_source):
+        self._url = url
+        self._traversal_source = traversal_source
+
+    @property
+    def url(self):
+        return self._url
+
+    @property
+    def traversal_source(self):
+        return self._traversal_source
+
+    @abc.abstractmethod
+    def submit(self, bytecode):
+        pass
+
+    def __repr__(self):
+        return "remoteconnection[" + self._url + "," + self._traversal_source + "]"
+
+
+class RemoteTraversal(traversal.Traversal):
+    def __init__(self, traversers, side_effects):
+        super(RemoteTraversal, self).__init__(None, None, None)
+        self.traversers = traversers
+        self._side_effects = side_effects
+
+    @property
+    def side_effects(self):
+        return self._side_effects
+
+    @side_effects.setter
+    def side_effects(self, val):
+        self._side_effects = val
+
+
+class RemoteStrategy(traversal.TraversalStrategy):
+    def __init__(self, remote_connection):
+        self.remote_connection = remote_connection
+
+    async def apply(self, traversal):
+        if traversal.traversers is None:
+            remote_traversal = await self.remote_connection.submit(
+                traversal.bytecode)
+            traversal.remote_results = remote_traversal
+            traversal.side_effects = remote_traversal.side_effects
+            traversal.traversers = remote_traversal.traversers
diff --git a/aiogremlin/gremlin_python/driver/request.py b/aiogremlin/gremlin_python/driver/request.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac7b845c659013ac13ace9c6dca1f75076b86ee8
--- /dev/null
+++ b/aiogremlin/gremlin_python/driver/request.py
@@ -0,0 +1,25 @@
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 collections
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+RequestMessage = collections.namedtuple(
+    'RequestMessage', ['processor', 'op', 'args'])
diff --git a/aiogremlin/gremlin_python/driver/serializer.py b/aiogremlin/gremlin_python/driver/serializer.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6c1e86ace1db586bc55f1525bf9d73cd5e23529
--- /dev/null
+++ b/aiogremlin/gremlin_python/driver/serializer.py
@@ -0,0 +1,130 @@
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+"""
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+try:
+    import ujson as json
+except ImportError:
+    import json
+
+from aiogremlin.gremlin_python.structure.io import graphson
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class Processor:
+    """Base class for OpProcessor serialization system."""
+
+    def __init__(self, writer):
+        self._graphson_writer = writer
+
+    def get_op_args(self, op, args):
+        op_method = getattr(self, op, None)
+        if not op_method:
+            raise Exception("Processor does not support op: {}".format(op))
+        return op_method(args)
+
+
+class Standard(Processor):
+
+    def authentication(self, args):
+        return args
+
+    def eval(self, args):
+        return args
+
+
+class Traversal(Processor):
+
+    def authentication(self, args):
+        return args
+
+    def bytecode(self, args):
+        gremlin = args['gremlin']
+        args['gremlin'] = self._graphson_writer.toDict(gremlin)
+        aliases = args.get('aliases', '')
+        if not aliases:
+            aliases = {'g': 'g'}
+        args['aliases'] = aliases
+        return args
+
+    def close(self, args):
+        return self.keys(args)
+
+    def gather(self, args):
+        side_effect = args['sideEffect']
+        args['sideEffect'] = {'@type': 'g:UUID', '@value': side_effect}
+        aliases = args.get('aliases', '')
+        if not aliases:
+            aliases = {'g': 'g'}
+        args['aliases'] = aliases
+        return args
+
+    def keys(self, args):
+        side_effect = args['sideEffect']
+        args['sideEffect'] = {'@type': 'g:UUID', '@value': side_effect}
+        return args
+
+
+class GraphSONMessageSerializer:
+    """Message serializer for GraphSON"""
+
+    def __init__(self, reader=None, writer=None):
+        if not reader:
+            reader = graphson.GraphSONReader()
+        self._graphson_reader = reader
+        if not writer:
+            writer = graphson.GraphSONWriter()
+        self.standard = Standard(writer)
+        self.traversal = Traversal(writer)
+
+    def get_processor(self, processor):
+        processor = getattr(self, processor, None)
+        if not processor:
+            raise Exception("Unknown processor")
+        return processor
+
+    def serialize_message(self, request_id, request_message):
+        processor = request_message.processor
+        op = request_message.op
+        args = request_message.args
+        if not processor:
+            processor_obj = self.get_processor('standard')
+        else:
+            processor_obj = self.get_processor(processor)
+        args = processor_obj.get_op_args(op, args)
+        message = self.build_message(request_id, processor, op, args)
+        return message
+
+    def build_message(self, request_id, processor, op, args):
+        message = {
+            'requestId': {'@type': 'g:UUID', '@value': request_id},
+            'processor': processor,
+            'op': op,
+            'args': args
+        }
+        return self.finalize_message(message, b"\x21",
+                                     b"application/vnd.gremlin-v2.0+json")
+
+    def finalize_message(self, message, mime_len, mime_type):
+        message = json.dumps(message)
+        message = b''.join([mime_len, mime_type, message.encode('utf-8')])
+        return message
+
+    def deserialize_message(self, message):
+        return self._graphson_reader.toObject(message)
diff --git a/aiogremlin/gremlin_python/driver/transport.py b/aiogremlin/gremlin_python/driver/transport.py
new file mode 100644
index 0000000000000000000000000000000000000000..000028383fc4e34880ce4a46625b7fd57a7aa2db
--- /dev/null
+++ b/aiogremlin/gremlin_python/driver/transport.py
@@ -0,0 +1,45 @@
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 abc
+
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class AbstractBaseTransport(metaclass=abc.ABCMeta):
+
+    @abc.abstractmethod
+    def connect(self, url, *, ssl_context=None):
+        pass
+
+    @abc.abstractmethod
+    def write(self, message):
+        pass
+
+    @abc.abstractmethod
+    def read(self):
+        pass
+
+    @abc.abstractmethod
+    def close(self):
+        pass
+
+    @abc.abstractproperty
+    def closed(self):
+        pass
diff --git a/aiogremlin/gremlin_python/process/__init__.py b/aiogremlin/gremlin_python/process/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7626550738f12ccd5e18b8c06a8d68aaab882066
--- /dev/null
+++ b/aiogremlin/gremlin_python/process/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/aiogremlin/gremlin_python/process/graph_traversal.py b/aiogremlin/gremlin_python/process/graph_traversal.py
new file mode 100644
index 0000000000000000000000000000000000000000..0528178775b5c616d33e063a111dc05895c67767
--- /dev/null
+++ b/aiogremlin/gremlin_python/process/graph_traversal.py
@@ -0,0 +1,1129 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+import sys
+from aiogremlin.gremlin_python.process.traversal import Traversal
+from aiogremlin.gremlin_python.process.traversal import TraversalStrategies
+from aiogremlin.gremlin_python.process.strategies import VertexProgramStrategy
+from .traversal import Bytecode
+from aiogremlin.gremlin_python.driver.remote_connection import RemoteStrategy
+from aiogremlin.gremlin_python import statics
+from aiogremlin.gremlin_python.statics import long
+
+class GraphTraversalSource(object):
+  def __init__(self, graph, traversal_strategies, bytecode=None):
+    self.graph = graph
+    self.traversal_strategies = traversal_strategies
+    if bytecode is None:
+      bytecode = Bytecode()
+    self.bytecode = bytecode
+  def __repr__(self):
+    return "graphtraversalsource[" + str(self.graph) + "]"
+  def withBulk(self, *args):
+    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+    source.bytecode.add_source("withBulk", *args)
+    return source
+  def withPath(self, *args):
+    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+    source.bytecode.add_source("withPath", *args)
+    return source
+  def withSack(self, *args):
+    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+    source.bytecode.add_source("withSack", *args)
+    return source
+  def withSideEffect(self, *args):
+    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+    source.bytecode.add_source("withSideEffect", *args)
+    return source
+  def withStrategies(self, *args):
+    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+    source.bytecode.add_source("withStrategies", *args)
+    return source
+  def withoutStrategies(self, *args):
+    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+    source.bytecode.add_source("withoutStrategies", *args)
+    return source
+  def withRemote(self, remote_connection):
+    source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode))
+    source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)])
+    return source
+  def withComputer(self,graph_computer=None, workers=None, result=None, persist=None, vertices=None, edges=None, configuration=None):
+    return self.withStrategies(VertexProgramStrategy(graph_computer,workers,result,persist,vertices,edges,configuration))
+  def E(self, *args):
+    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal.bytecode.add_step("E", *args)
+    return traversal
+  def V(self, *args):
+    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal.bytecode.add_step("V", *args)
+    return traversal
+  def addV(self, *args):
+    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal.bytecode.add_step("addV", *args)
+    return traversal
+  def inject(self, *args):
+    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal.bytecode.add_step("inject", *args)
+    return traversal
+
+
+class GraphTraversal(Traversal):
+  def __init__(self, graph, traversal_strategies, bytecode):
+    Traversal.__init__(self, graph, traversal_strategies, bytecode)
+  def __getitem__(self, index):
+    if isinstance(index, int):
+        return self.range(long(index), long(index + 1))
+    elif isinstance(index, slice):
+        return self.range(long(0) if index.start is None else long(index.start), long(sys.maxsize) if index.stop is None else long(index.stop))
+    else:
+        raise TypeError("Index must be int or slice")
+  def __getattr__(self, key):
+    return self.values(key)
+  def V(self, *args):
+    self.bytecode.add_step("V", *args)
+    return self
+  def addE(self, *args):
+    self.bytecode.add_step("addE", *args)
+    return self
+  def addInE(self, *args):
+    self.bytecode.add_step("addInE", *args)
+    return self
+  def addOutE(self, *args):
+    self.bytecode.add_step("addOutE", *args)
+    return self
+  def addV(self, *args):
+    self.bytecode.add_step("addV", *args)
+    return self
+  def aggregate(self, *args):
+    self.bytecode.add_step("aggregate", *args)
+    return self
+  def and_(self, *args):
+    self.bytecode.add_step("and", *args)
+    return self
+  def as_(self, *args):
+    self.bytecode.add_step("as", *args)
+    return self
+  def barrier(self, *args):
+    self.bytecode.add_step("barrier", *args)
+    return self
+  def both(self, *args):
+    self.bytecode.add_step("both", *args)
+    return self
+  def bothE(self, *args):
+    self.bytecode.add_step("bothE", *args)
+    return self
+  def bothV(self, *args):
+    self.bytecode.add_step("bothV", *args)
+    return self
+  def branch(self, *args):
+    self.bytecode.add_step("branch", *args)
+    return self
+  def by(self, *args):
+    self.bytecode.add_step("by", *args)
+    return self
+  def cap(self, *args):
+    self.bytecode.add_step("cap", *args)
+    return self
+  def choose(self, *args):
+    self.bytecode.add_step("choose", *args)
+    return self
+  def coalesce(self, *args):
+    self.bytecode.add_step("coalesce", *args)
+    return self
+  def coin(self, *args):
+    self.bytecode.add_step("coin", *args)
+    return self
+  def constant(self, *args):
+    self.bytecode.add_step("constant", *args)
+    return self
+  def count(self, *args):
+    self.bytecode.add_step("count", *args)
+    return self
+  def cyclicPath(self, *args):
+    self.bytecode.add_step("cyclicPath", *args)
+    return self
+  def dedup(self, *args):
+    self.bytecode.add_step("dedup", *args)
+    return self
+  def drop(self, *args):
+    self.bytecode.add_step("drop", *args)
+    return self
+  def emit(self, *args):
+    self.bytecode.add_step("emit", *args)
+    return self
+  def filter(self, *args):
+    self.bytecode.add_step("filter", *args)
+    return self
+  def flatMap(self, *args):
+    self.bytecode.add_step("flatMap", *args)
+    return self
+  def fold(self, *args):
+    self.bytecode.add_step("fold", *args)
+    return self
+  def from_(self, *args):
+    self.bytecode.add_step("from", *args)
+    return self
+  def group(self, *args):
+    self.bytecode.add_step("group", *args)
+    return self
+  def groupCount(self, *args):
+    self.bytecode.add_step("groupCount", *args)
+    return self
+  def groupV3d0(self, *args):
+    self.bytecode.add_step("groupV3d0", *args)
+    return self
+  def has(self, *args):
+    self.bytecode.add_step("has", *args)
+    return self
+  def hasId(self, *args):
+    self.bytecode.add_step("hasId", *args)
+    return self
+  def hasKey(self, *args):
+    self.bytecode.add_step("hasKey", *args)
+    return self
+  def hasLabel(self, *args):
+    self.bytecode.add_step("hasLabel", *args)
+    return self
+  def hasNot(self, *args):
+    self.bytecode.add_step("hasNot", *args)
+    return self
+  def hasValue(self, *args):
+    self.bytecode.add_step("hasValue", *args)
+    return self
+  def id(self, *args):
+    self.bytecode.add_step("id", *args)
+    return self
+  def identity(self, *args):
+    self.bytecode.add_step("identity", *args)
+    return self
+  def inE(self, *args):
+    self.bytecode.add_step("inE", *args)
+    return self
+  def inV(self, *args):
+    self.bytecode.add_step("inV", *args)
+    return self
+  def in_(self, *args):
+    self.bytecode.add_step("in", *args)
+    return self
+  def inject(self, *args):
+    self.bytecode.add_step("inject", *args)
+    return self
+  def is_(self, *args):
+    self.bytecode.add_step("is", *args)
+    return self
+  def key(self, *args):
+    self.bytecode.add_step("key", *args)
+    return self
+  def label(self, *args):
+    self.bytecode.add_step("label", *args)
+    return self
+  def limit(self, *args):
+    self.bytecode.add_step("limit", *args)
+    return self
+  def local(self, *args):
+    self.bytecode.add_step("local", *args)
+    return self
+  def loops(self, *args):
+    self.bytecode.add_step("loops", *args)
+    return self
+  def map(self, *args):
+    self.bytecode.add_step("map", *args)
+    return self
+  def mapKeys(self, *args):
+    self.bytecode.add_step("mapKeys", *args)
+    return self
+  def mapValues(self, *args):
+    self.bytecode.add_step("mapValues", *args)
+    return self
+  def match(self, *args):
+    self.bytecode.add_step("match", *args)
+    return self
+  def max(self, *args):
+    self.bytecode.add_step("max", *args)
+    return self
+  def mean(self, *args):
+    self.bytecode.add_step("mean", *args)
+    return self
+  def min(self, *args):
+    self.bytecode.add_step("min", *args)
+    return self
+  def not_(self, *args):
+    self.bytecode.add_step("not", *args)
+    return self
+  def option(self, *args):
+    self.bytecode.add_step("option", *args)
+    return self
+  def optional(self, *args):
+    self.bytecode.add_step("optional", *args)
+    return self
+  def or_(self, *args):
+    self.bytecode.add_step("or", *args)
+    return self
+  def order(self, *args):
+    self.bytecode.add_step("order", *args)
+    return self
+  def otherV(self, *args):
+    self.bytecode.add_step("otherV", *args)
+    return self
+  def out(self, *args):
+    self.bytecode.add_step("out", *args)
+    return self
+  def outE(self, *args):
+    self.bytecode.add_step("outE", *args)
+    return self
+  def outV(self, *args):
+    self.bytecode.add_step("outV", *args)
+    return self
+  def pageRank(self, *args):
+    self.bytecode.add_step("pageRank", *args)
+    return self
+  def path(self, *args):
+    self.bytecode.add_step("path", *args)
+    return self
+  def peerPressure(self, *args):
+    self.bytecode.add_step("peerPressure", *args)
+    return self
+  def profile(self, *args):
+    self.bytecode.add_step("profile", *args)
+    return self
+  def program(self, *args):
+    self.bytecode.add_step("program", *args)
+    return self
+  def project(self, *args):
+    self.bytecode.add_step("project", *args)
+    return self
+  def properties(self, *args):
+    self.bytecode.add_step("properties", *args)
+    return self
+  def property(self, *args):
+    self.bytecode.add_step("property", *args)
+    return self
+  def propertyMap(self, *args):
+    self.bytecode.add_step("propertyMap", *args)
+    return self
+  def range(self, *args):
+    self.bytecode.add_step("range", *args)
+    return self
+  def repeat(self, *args):
+    self.bytecode.add_step("repeat", *args)
+    return self
+  def sack(self, *args):
+    self.bytecode.add_step("sack", *args)
+    return self
+  def sample(self, *args):
+    self.bytecode.add_step("sample", *args)
+    return self
+  def select(self, *args):
+    self.bytecode.add_step("select", *args)
+    return self
+  def sideEffect(self, *args):
+    self.bytecode.add_step("sideEffect", *args)
+    return self
+  def simplePath(self, *args):
+    self.bytecode.add_step("simplePath", *args)
+    return self
+  def store(self, *args):
+    self.bytecode.add_step("store", *args)
+    return self
+  def subgraph(self, *args):
+    self.bytecode.add_step("subgraph", *args)
+    return self
+  def sum(self, *args):
+    self.bytecode.add_step("sum", *args)
+    return self
+  def tail(self, *args):
+    self.bytecode.add_step("tail", *args)
+    return self
+  def timeLimit(self, *args):
+    self.bytecode.add_step("timeLimit", *args)
+    return self
+  def times(self, *args):
+    self.bytecode.add_step("times", *args)
+    return self
+  def to(self, *args):
+    self.bytecode.add_step("to", *args)
+    return self
+  def toE(self, *args):
+    self.bytecode.add_step("toE", *args)
+    return self
+  def toV(self, *args):
+    self.bytecode.add_step("toV", *args)
+    return self
+  def tree(self, *args):
+    self.bytecode.add_step("tree", *args)
+    return self
+  def unfold(self, *args):
+    self.bytecode.add_step("unfold", *args)
+    return self
+  def union(self, *args):
+    self.bytecode.add_step("union", *args)
+    return self
+  def until(self, *args):
+    self.bytecode.add_step("until", *args)
+    return self
+  def value(self, *args):
+    self.bytecode.add_step("value", *args)
+    return self
+  def valueMap(self, *args):
+    self.bytecode.add_step("valueMap", *args)
+    return self
+  def values(self, *args):
+    self.bytecode.add_step("values", *args)
+    return self
+  def where(self, *args):
+    self.bytecode.add_step("where", *args)
+    return self
+
+
+class __(object):
+  @staticmethod
+  def start():
+    return GraphTraversal(None, None, Bytecode())
+  @staticmethod
+  def __(*args):
+    return __.inject(*args)
+  @staticmethod
+  def V(*args):
+    return GraphTraversal(None, None, Bytecode()).V(*args)
+  @staticmethod
+  def addE(*args):
+    return GraphTraversal(None, None, Bytecode()).addE(*args)
+  @staticmethod
+  def addInE(*args):
+    return GraphTraversal(None, None, Bytecode()).addInE(*args)
+  @staticmethod
+  def addOutE(*args):
+    return GraphTraversal(None, None, Bytecode()).addOutE(*args)
+  @staticmethod
+  def addV(*args):
+    return GraphTraversal(None, None, Bytecode()).addV(*args)
+  @staticmethod
+  def aggregate(*args):
+    return GraphTraversal(None, None, Bytecode()).aggregate(*args)
+  @staticmethod
+  def and_(*args):
+    return GraphTraversal(None, None, Bytecode()).and_(*args)
+  @staticmethod
+  def as_(*args):
+    return GraphTraversal(None, None, Bytecode()).as_(*args)
+  @staticmethod
+  def barrier(*args):
+    return GraphTraversal(None, None, Bytecode()).barrier(*args)
+  @staticmethod
+  def both(*args):
+    return GraphTraversal(None, None, Bytecode()).both(*args)
+  @staticmethod
+  def bothE(*args):
+    return GraphTraversal(None, None, Bytecode()).bothE(*args)
+  @staticmethod
+  def bothV(*args):
+    return GraphTraversal(None, None, Bytecode()).bothV(*args)
+  @staticmethod
+  def branch(*args):
+    return GraphTraversal(None, None, Bytecode()).branch(*args)
+  @staticmethod
+  def cap(*args):
+    return GraphTraversal(None, None, Bytecode()).cap(*args)
+  @staticmethod
+  def choose(*args):
+    return GraphTraversal(None, None, Bytecode()).choose(*args)
+  @staticmethod
+  def coalesce(*args):
+    return GraphTraversal(None, None, Bytecode()).coalesce(*args)
+  @staticmethod
+  def coin(*args):
+    return GraphTraversal(None, None, Bytecode()).coin(*args)
+  @staticmethod
+  def constant(*args):
+    return GraphTraversal(None, None, Bytecode()).constant(*args)
+  @staticmethod
+  def count(*args):
+    return GraphTraversal(None, None, Bytecode()).count(*args)
+  @staticmethod
+  def cyclicPath(*args):
+    return GraphTraversal(None, None, Bytecode()).cyclicPath(*args)
+  @staticmethod
+  def dedup(*args):
+    return GraphTraversal(None, None, Bytecode()).dedup(*args)
+  @staticmethod
+  def drop(*args):
+    return GraphTraversal(None, None, Bytecode()).drop(*args)
+  @staticmethod
+  def emit(*args):
+    return GraphTraversal(None, None, Bytecode()).emit(*args)
+  @staticmethod
+  def filter(*args):
+    return GraphTraversal(None, None, Bytecode()).filter(*args)
+  @staticmethod
+  def flatMap(*args):
+    return GraphTraversal(None, None, Bytecode()).flatMap(*args)
+  @staticmethod
+  def fold(*args):
+    return GraphTraversal(None, None, Bytecode()).fold(*args)
+  @staticmethod
+  def group(*args):
+    return GraphTraversal(None, None, Bytecode()).group(*args)
+  @staticmethod
+  def groupCount(*args):
+    return GraphTraversal(None, None, Bytecode()).groupCount(*args)
+  @staticmethod
+  def groupV3d0(*args):
+    return GraphTraversal(None, None, Bytecode()).groupV3d0(*args)
+  @staticmethod
+  def has(*args):
+    return GraphTraversal(None, None, Bytecode()).has(*args)
+  @staticmethod
+  def hasId(*args):
+    return GraphTraversal(None, None, Bytecode()).hasId(*args)
+  @staticmethod
+  def hasKey(*args):
+    return GraphTraversal(None, None, Bytecode()).hasKey(*args)
+  @staticmethod
+  def hasLabel(*args):
+    return GraphTraversal(None, None, Bytecode()).hasLabel(*args)
+  @staticmethod
+  def hasNot(*args):
+    return GraphTraversal(None, None, Bytecode()).hasNot(*args)
+  @staticmethod
+  def hasValue(*args):
+    return GraphTraversal(None, None, Bytecode()).hasValue(*args)
+  @staticmethod
+  def id(*args):
+    return GraphTraversal(None, None, Bytecode()).id(*args)
+  @staticmethod
+  def identity(*args):
+    return GraphTraversal(None, None, Bytecode()).identity(*args)
+  @staticmethod
+  def inE(*args):
+    return GraphTraversal(None, None, Bytecode()).inE(*args)
+  @staticmethod
+  def inV(*args):
+    return GraphTraversal(None, None, Bytecode()).inV(*args)
+  @staticmethod
+  def in_(*args):
+    return GraphTraversal(None, None, Bytecode()).in_(*args)
+  @staticmethod
+  def inject(*args):
+    return GraphTraversal(None, None, Bytecode()).inject(*args)
+  @staticmethod
+  def is_(*args):
+    return GraphTraversal(None, None, Bytecode()).is_(*args)
+  @staticmethod
+  def key(*args):
+    return GraphTraversal(None, None, Bytecode()).key(*args)
+  @staticmethod
+  def label(*args):
+    return GraphTraversal(None, None, Bytecode()).label(*args)
+  @staticmethod
+  def limit(*args):
+    return GraphTraversal(None, None, Bytecode()).limit(*args)
+  @staticmethod
+  def local(*args):
+    return GraphTraversal(None, None, Bytecode()).local(*args)
+  @staticmethod
+  def loops(*args):
+    return GraphTraversal(None, None, Bytecode()).loops(*args)
+  @staticmethod
+  def map(*args):
+    return GraphTraversal(None, None, Bytecode()).map(*args)
+  @staticmethod
+  def mapKeys(*args):
+    return GraphTraversal(None, None, Bytecode()).mapKeys(*args)
+  @staticmethod
+  def mapValues(*args):
+    return GraphTraversal(None, None, Bytecode()).mapValues(*args)
+  @staticmethod
+  def match(*args):
+    return GraphTraversal(None, None, Bytecode()).match(*args)
+  @staticmethod
+  def max(*args):
+    return GraphTraversal(None, None, Bytecode()).max(*args)
+  @staticmethod
+  def mean(*args):
+    return GraphTraversal(None, None, Bytecode()).mean(*args)
+  @staticmethod
+  def min(*args):
+    return GraphTraversal(None, None, Bytecode()).min(*args)
+  @staticmethod
+  def not_(*args):
+    return GraphTraversal(None, None, Bytecode()).not_(*args)
+  @staticmethod
+  def optional(*args):
+    return GraphTraversal(None, None, Bytecode()).optional(*args)
+  @staticmethod
+  def or_(*args):
+    return GraphTraversal(None, None, Bytecode()).or_(*args)
+  @staticmethod
+  def order(*args):
+    return GraphTraversal(None, None, Bytecode()).order(*args)
+  @staticmethod
+  def otherV(*args):
+    return GraphTraversal(None, None, Bytecode()).otherV(*args)
+  @staticmethod
+  def out(*args):
+    return GraphTraversal(None, None, Bytecode()).out(*args)
+  @staticmethod
+  def outE(*args):
+    return GraphTraversal(None, None, Bytecode()).outE(*args)
+  @staticmethod
+  def outV(*args):
+    return GraphTraversal(None, None, Bytecode()).outV(*args)
+  @staticmethod
+  def path(*args):
+    return GraphTraversal(None, None, Bytecode()).path(*args)
+  @staticmethod
+  def project(*args):
+    return GraphTraversal(None, None, Bytecode()).project(*args)
+  @staticmethod
+  def properties(*args):
+    return GraphTraversal(None, None, Bytecode()).properties(*args)
+  @staticmethod
+  def property(*args):
+    return GraphTraversal(None, None, Bytecode()).property(*args)
+  @staticmethod
+  def propertyMap(*args):
+    return GraphTraversal(None, None, Bytecode()).propertyMap(*args)
+  @staticmethod
+  def range(*args):
+    return GraphTraversal(None, None, Bytecode()).range(*args)
+  @staticmethod
+  def repeat(*args):
+    return GraphTraversal(None, None, Bytecode()).repeat(*args)
+  @staticmethod
+  def sack(*args):
+    return GraphTraversal(None, None, Bytecode()).sack(*args)
+  @staticmethod
+  def sample(*args):
+    return GraphTraversal(None, None, Bytecode()).sample(*args)
+  @staticmethod
+  def select(*args):
+    return GraphTraversal(None, None, Bytecode()).select(*args)
+  @staticmethod
+  def sideEffect(*args):
+    return GraphTraversal(None, None, Bytecode()).sideEffect(*args)
+  @staticmethod
+  def simplePath(*args):
+    return GraphTraversal(None, None, Bytecode()).simplePath(*args)
+  @staticmethod
+  def store(*args):
+    return GraphTraversal(None, None, Bytecode()).store(*args)
+  @staticmethod
+  def subgraph(*args):
+    return GraphTraversal(None, None, Bytecode()).subgraph(*args)
+  @staticmethod
+  def sum(*args):
+    return GraphTraversal(None, None, Bytecode()).sum(*args)
+  @staticmethod
+  def tail(*args):
+    return GraphTraversal(None, None, Bytecode()).tail(*args)
+  @staticmethod
+  def timeLimit(*args):
+    return GraphTraversal(None, None, Bytecode()).timeLimit(*args)
+  @staticmethod
+  def times(*args):
+    return GraphTraversal(None, None, Bytecode()).times(*args)
+  @staticmethod
+  def to(*args):
+    return GraphTraversal(None, None, Bytecode()).to(*args)
+  @staticmethod
+  def toE(*args):
+    return GraphTraversal(None, None, Bytecode()).toE(*args)
+  @staticmethod
+  def toV(*args):
+    return GraphTraversal(None, None, Bytecode()).toV(*args)
+  @staticmethod
+  def tree(*args):
+    return GraphTraversal(None, None, Bytecode()).tree(*args)
+  @staticmethod
+  def unfold(*args):
+    return GraphTraversal(None, None, Bytecode()).unfold(*args)
+  @staticmethod
+  def union(*args):
+    return GraphTraversal(None, None, Bytecode()).union(*args)
+  @staticmethod
+  def until(*args):
+    return GraphTraversal(None, None, Bytecode()).until(*args)
+  @staticmethod
+  def value(*args):
+    return GraphTraversal(None, None, Bytecode()).value(*args)
+  @staticmethod
+  def valueMap(*args):
+    return GraphTraversal(None, None, Bytecode()).valueMap(*args)
+  @staticmethod
+  def values(*args):
+    return GraphTraversal(None, None, Bytecode()).values(*args)
+  @staticmethod
+  def where(*args):
+    return GraphTraversal(None, None, Bytecode()).where(*args)
+
+
+def V(*args):
+      return __.V(*args)
+
+statics.add_static('V', V)
+
+def addE(*args):
+      return __.addE(*args)
+
+statics.add_static('addE', addE)
+
+def addInE(*args):
+      return __.addInE(*args)
+
+statics.add_static('addInE', addInE)
+
+def addOutE(*args):
+      return __.addOutE(*args)
+
+statics.add_static('addOutE', addOutE)
+
+def addV(*args):
+      return __.addV(*args)
+
+statics.add_static('addV', addV)
+
+def aggregate(*args):
+      return __.aggregate(*args)
+
+statics.add_static('aggregate', aggregate)
+
+def and_(*args):
+      return __.and_(*args)
+
+statics.add_static('and_', and_)
+
+def as_(*args):
+      return __.as_(*args)
+
+statics.add_static('as_', as_)
+
+def barrier(*args):
+      return __.barrier(*args)
+
+statics.add_static('barrier', barrier)
+
+def both(*args):
+      return __.both(*args)
+
+statics.add_static('both', both)
+
+def bothE(*args):
+      return __.bothE(*args)
+
+statics.add_static('bothE', bothE)
+
+def bothV(*args):
+      return __.bothV(*args)
+
+statics.add_static('bothV', bothV)
+
+def branch(*args):
+      return __.branch(*args)
+
+statics.add_static('branch', branch)
+
+def cap(*args):
+      return __.cap(*args)
+
+statics.add_static('cap', cap)
+
+def choose(*args):
+      return __.choose(*args)
+
+statics.add_static('choose', choose)
+
+def coalesce(*args):
+      return __.coalesce(*args)
+
+statics.add_static('coalesce', coalesce)
+
+def coin(*args):
+      return __.coin(*args)
+
+statics.add_static('coin', coin)
+
+def constant(*args):
+      return __.constant(*args)
+
+statics.add_static('constant', constant)
+
+def count(*args):
+      return __.count(*args)
+
+statics.add_static('count', count)
+
+def cyclicPath(*args):
+      return __.cyclicPath(*args)
+
+statics.add_static('cyclicPath', cyclicPath)
+
+def dedup(*args):
+      return __.dedup(*args)
+
+statics.add_static('dedup', dedup)
+
+def drop(*args):
+      return __.drop(*args)
+
+statics.add_static('drop', drop)
+
+def emit(*args):
+      return __.emit(*args)
+
+statics.add_static('emit', emit)
+
+def filter(*args):
+      return __.filter(*args)
+
+statics.add_static('filter', filter)
+
+def flatMap(*args):
+      return __.flatMap(*args)
+
+statics.add_static('flatMap', flatMap)
+
+def fold(*args):
+      return __.fold(*args)
+
+statics.add_static('fold', fold)
+
+def group(*args):
+      return __.group(*args)
+
+statics.add_static('group', group)
+
+def groupCount(*args):
+      return __.groupCount(*args)
+
+statics.add_static('groupCount', groupCount)
+
+def groupV3d0(*args):
+      return __.groupV3d0(*args)
+
+statics.add_static('groupV3d0', groupV3d0)
+
+def has(*args):
+      return __.has(*args)
+
+statics.add_static('has', has)
+
+def hasId(*args):
+      return __.hasId(*args)
+
+statics.add_static('hasId', hasId)
+
+def hasKey(*args):
+      return __.hasKey(*args)
+
+statics.add_static('hasKey', hasKey)
+
+def hasLabel(*args):
+      return __.hasLabel(*args)
+
+statics.add_static('hasLabel', hasLabel)
+
+def hasNot(*args):
+      return __.hasNot(*args)
+
+statics.add_static('hasNot', hasNot)
+
+def hasValue(*args):
+      return __.hasValue(*args)
+
+statics.add_static('hasValue', hasValue)
+
+def id(*args):
+      return __.id(*args)
+
+statics.add_static('id', id)
+
+def identity(*args):
+      return __.identity(*args)
+
+statics.add_static('identity', identity)
+
+def inE(*args):
+      return __.inE(*args)
+
+statics.add_static('inE', inE)
+
+def inV(*args):
+      return __.inV(*args)
+
+statics.add_static('inV', inV)
+
+def in_(*args):
+      return __.in_(*args)
+
+statics.add_static('in_', in_)
+
+def inject(*args):
+      return __.inject(*args)
+
+statics.add_static('inject', inject)
+
+def is_(*args):
+      return __.is_(*args)
+
+statics.add_static('is_', is_)
+
+def key(*args):
+      return __.key(*args)
+
+statics.add_static('key', key)
+
+def label(*args):
+      return __.label(*args)
+
+statics.add_static('label', label)
+
+def limit(*args):
+      return __.limit(*args)
+
+statics.add_static('limit', limit)
+
+def local(*args):
+      return __.local(*args)
+
+statics.add_static('local', local)
+
+def loops(*args):
+      return __.loops(*args)
+
+statics.add_static('loops', loops)
+
+def map(*args):
+      return __.map(*args)
+
+statics.add_static('map', map)
+
+def mapKeys(*args):
+      return __.mapKeys(*args)
+
+statics.add_static('mapKeys', mapKeys)
+
+def mapValues(*args):
+      return __.mapValues(*args)
+
+statics.add_static('mapValues', mapValues)
+
+def match(*args):
+      return __.match(*args)
+
+statics.add_static('match', match)
+
+def max(*args):
+      return __.max(*args)
+
+statics.add_static('max', max)
+
+def mean(*args):
+      return __.mean(*args)
+
+statics.add_static('mean', mean)
+
+def min(*args):
+      return __.min(*args)
+
+statics.add_static('min', min)
+
+def not_(*args):
+      return __.not_(*args)
+
+statics.add_static('not_', not_)
+
+def optional(*args):
+      return __.optional(*args)
+
+statics.add_static('optional', optional)
+
+def or_(*args):
+      return __.or_(*args)
+
+statics.add_static('or_', or_)
+
+def order(*args):
+      return __.order(*args)
+
+statics.add_static('order', order)
+
+def otherV(*args):
+      return __.otherV(*args)
+
+statics.add_static('otherV', otherV)
+
+def out(*args):
+      return __.out(*args)
+
+statics.add_static('out', out)
+
+def outE(*args):
+      return __.outE(*args)
+
+statics.add_static('outE', outE)
+
+def outV(*args):
+      return __.outV(*args)
+
+statics.add_static('outV', outV)
+
+def path(*args):
+      return __.path(*args)
+
+statics.add_static('path', path)
+
+def project(*args):
+      return __.project(*args)
+
+statics.add_static('project', project)
+
+def properties(*args):
+      return __.properties(*args)
+
+statics.add_static('properties', properties)
+
+def property(*args):
+      return __.property(*args)
+
+statics.add_static('property', property)
+
+def propertyMap(*args):
+      return __.propertyMap(*args)
+
+statics.add_static('propertyMap', propertyMap)
+
+def range(*args):
+      return __.range(*args)
+
+statics.add_static('range', range)
+
+def repeat(*args):
+      return __.repeat(*args)
+
+statics.add_static('repeat', repeat)
+
+def sack(*args):
+      return __.sack(*args)
+
+statics.add_static('sack', sack)
+
+def sample(*args):
+      return __.sample(*args)
+
+statics.add_static('sample', sample)
+
+def select(*args):
+      return __.select(*args)
+
+statics.add_static('select', select)
+
+def sideEffect(*args):
+      return __.sideEffect(*args)
+
+statics.add_static('sideEffect', sideEffect)
+
+def simplePath(*args):
+      return __.simplePath(*args)
+
+statics.add_static('simplePath', simplePath)
+
+def store(*args):
+      return __.store(*args)
+
+statics.add_static('store', store)
+
+def subgraph(*args):
+      return __.subgraph(*args)
+
+statics.add_static('subgraph', subgraph)
+
+def sum(*args):
+      return __.sum(*args)
+
+statics.add_static('sum', sum)
+
+def tail(*args):
+      return __.tail(*args)
+
+statics.add_static('tail', tail)
+
+def timeLimit(*args):
+      return __.timeLimit(*args)
+
+statics.add_static('timeLimit', timeLimit)
+
+def times(*args):
+      return __.times(*args)
+
+statics.add_static('times', times)
+
+def to(*args):
+      return __.to(*args)
+
+statics.add_static('to', to)
+
+def toE(*args):
+      return __.toE(*args)
+
+statics.add_static('toE', toE)
+
+def toV(*args):
+      return __.toV(*args)
+
+statics.add_static('toV', toV)
+
+def tree(*args):
+      return __.tree(*args)
+
+statics.add_static('tree', tree)
+
+def unfold(*args):
+      return __.unfold(*args)
+
+statics.add_static('unfold', unfold)
+
+def union(*args):
+      return __.union(*args)
+
+statics.add_static('union', union)
+
+def until(*args):
+      return __.until(*args)
+
+statics.add_static('until', until)
+
+def value(*args):
+      return __.value(*args)
+
+statics.add_static('value', value)
+
+def valueMap(*args):
+      return __.valueMap(*args)
+
+statics.add_static('valueMap', valueMap)
+
+def values(*args):
+      return __.values(*args)
+
+statics.add_static('values', values)
+
+def where(*args):
+      return __.where(*args)
+
+statics.add_static('where', where)
diff --git a/aiogremlin/gremlin_python/process/strategies.py b/aiogremlin/gremlin_python/process/strategies.py
new file mode 100644
index 0000000000000000000000000000000000000000..1ac779d5156be617e2fd300e9c0edcc3f75f5eee
--- /dev/null
+++ b/aiogremlin/gremlin_python/process/strategies.py
@@ -0,0 +1,184 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+from aiogremlin.gremlin_python.process.traversal import TraversalStrategy
+
+
+#########################
+# DECORATION STRATEGIES #
+#########################
+
+class ConnectiveStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class ElementIdStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+# EventStrategy doesn't make sense outside JVM traversal machine
+
+class HaltedTraverserStrategy(TraversalStrategy):
+    def __init__(self, halted_traverser_factory=None):
+        TraversalStrategy.__init__(self)
+        if halted_traverser_factory is not None:
+            self.configuration["haltedTraverserFactory"] = halted_traverser_factory
+
+
+class PartitionStrategy(TraversalStrategy):
+    def __init__(self, partition_key=None, write_partition=None, read_partitions=None, include_meta_properties=None):
+        TraversalStrategy.__init__(self)
+        if partition_key is not None:
+            self.configuration["partitionKey"] = partition_key
+        if write_partition is not None:
+            self.configuration["writePartition"] = write_partition
+        if write_partition is not None:
+            self.configuration["readPartitions"] = read_partitions
+        if include_meta_properties is not None:
+            self.configuration["includeMetaProperties"] = include_meta_properties
+
+
+class SubgraphStrategy(TraversalStrategy):
+    def __init__(self, vertices=None, edges=None, vertex_properties=None):
+        TraversalStrategy.__init__(self)
+        if vertices is not None:
+            self.configuration["vertices"] = vertices
+        if edges is not None:
+            self.configuration["edges"] = edges
+        if vertex_properties is not None:
+            self.configuration["vertexProperties"] = vertex_properties
+
+
+class VertexProgramStrategy(TraversalStrategy):
+    def __init__(self, graph_computer=None, workers=None, persist=None, result=None, vertices=None, edges=None,
+                 configuration=None):
+        TraversalStrategy.__init__(self)
+        if graph_computer is not None:
+            self.configuration["graphComputer"] = graph_computer
+        if workers is not None:
+            self.configuration["workers"] = workers
+        if persist is not None:
+            self.configuration["persist"] = persist
+        if result is not None:
+            self.configuration["result"] = result
+        if vertices is not None:
+            self.configuration["vertices"] = vertices
+        if edges is not None:
+            self.configuration["edges"] = edges
+        if configuration is not None:
+            self.configuration.update(configuration)
+
+
+###########################
+# FINALIZATION STRATEGIES #
+###########################
+
+class MatchAlgorithmStrategy(TraversalStrategy):
+    def __init__(self, match_algorithm=None):
+        TraversalStrategy.__init__(self)
+        if match_algorithm is not None:
+            self.configuration["matchAlgorithm"] = match_algorithm
+
+
+###########################
+# OPTIMIZATION STRATEGIES #
+###########################
+
+class AdjacentToIncidentStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class FilterRankingStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class IdentityRemoveStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class IncidentToAdjacentStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class InlineFilterStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class LazyBarrierStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class MatchPredicateStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class OrderLimitStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class PathProcessorStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class PathRetractionStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class RangeByIsCountStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class RepeatUnrollStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class GraphFilterStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+###########################
+# VERIFICATION STRATEGIES #
+###########################
+
+class LambdaRestrictionStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class ReadOnlyStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
diff --git a/aiogremlin/gremlin_python/process/traversal.py b/aiogremlin/gremlin_python/process/traversal.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e3290fa68ebe5035de29144726e492c6bc1d2e9
--- /dev/null
+++ b/aiogremlin/gremlin_python/process/traversal.py
@@ -0,0 +1,396 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+import asyncio
+from enum import Enum
+from aiogremlin.gremlin_python import statics
+
+
+class Traversal(object):
+    def __init__(self, graph, traversal_strategies, bytecode):
+        self.graph = graph
+        self.traversal_strategies = traversal_strategies
+        self.bytecode = bytecode
+        self.side_effects = TraversalSideEffects()
+        self.traversers = None
+        self.last_traverser = None
+    def __repr__(self):
+        return str(self.bytecode)
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.bytecode == other.bytecode
+        else:
+            return False
+    async def __aiter__(self):
+        return self
+    async def __anext__(self):
+        if self.traversers is None:
+            await self.traversal_strategies.apply_strategies(self)
+        if self.last_traverser is None:
+            self.last_traverser = await self.traversers.__anext__()
+        object = self.last_traverser.object
+        self.last_traverser.bulk = self.last_traverser.bulk - 1
+        if self.last_traverser.bulk <= 0:
+            self.last_traverser = None
+        return object
+    async def toList(self):
+        results = []
+        async for result in self:
+            results.append(result)
+        return results
+    async def toSet(self):
+        results = set()
+        async for result in self:
+            results.add(result)
+        return results
+    async def iterate(self):
+        while True:
+            try:
+                await self.nextTraverser()
+            except StopAsyncIteration:
+                return self
+    async def nextTraverser(self):
+        if self.traversers is None:
+            await self.traversal_strategies.apply_strategies(self)
+        if self.last_traverser is None:
+            return await self.traversers.__anext__()
+        else:
+            temp = self.last_traverser
+            self.last_traverser = None
+            return temp
+    async def next(self, amount=None):
+        if amount is None:
+            return await self.__anext__()
+        else:
+            count = 0
+            tempList = []
+            while count < amount:
+                count = count + 1
+                try:
+                    temp = await self.__anext__()
+                except StopAsyncIteration:
+                    return tempList
+                tempList.append(temp)
+            return tempList
+
+
+Barrier = Enum('Barrier', 'normSack')
+statics.add_static('normSack', Barrier.normSack)
+
+Cardinality = Enum('Cardinality', 'list_ set_ single')
+statics.add_static('single', Cardinality.single)
+statics.add_static('list_', Cardinality.list_)
+statics.add_static('set_', Cardinality.set_)
+
+Column = Enum('Column', 'keys values')
+statics.add_static('keys', Column.keys)
+statics.add_static('values', Column.values)
+
+Direction = Enum('Direction', 'BOTH IN OUT')
+statics.add_static('OUT', Direction.OUT)
+statics.add_static('IN', Direction.IN)
+statics.add_static('BOTH', Direction.BOTH)
+
+Operator = Enum('Operator', 'addAll and_ assign div max min minus mult or_ sum sumLong')
+statics.add_static('sum', Operator.sum)
+statics.add_static('minus', Operator.minus)
+statics.add_static('mult', Operator.mult)
+statics.add_static('div', Operator.div)
+statics.add_static('min', Operator.min)
+statics.add_static('max', Operator.max)
+statics.add_static('assign', Operator.assign)
+statics.add_static('and_', Operator.and_)
+statics.add_static('or_', Operator.or_)
+statics.add_static('addAll', Operator.addAll)
+statics.add_static('sumLong', Operator.sumLong)
+
+Order = Enum('Order', 'decr incr keyDecr keyIncr shuffle valueDecr valueIncr')
+statics.add_static('incr', Order.incr)
+statics.add_static('decr', Order.decr)
+statics.add_static('keyIncr', Order.keyIncr)
+statics.add_static('valueIncr', Order.valueIncr)
+statics.add_static('keyDecr', Order.keyDecr)
+statics.add_static('valueDecr', Order.valueDecr)
+statics.add_static('shuffle', Order.shuffle)
+
+Pick = Enum('Pick', 'any none')
+statics.add_static('any', Pick.any)
+statics.add_static('none', Pick.none)
+
+Pop = Enum('Pop', 'all_ first last')
+statics.add_static('first', Pop.first)
+statics.add_static('last', Pop.last)
+statics.add_static('all_', Pop.all_)
+
+Scope = Enum('Scope', 'global_ local')
+statics.add_static('global_', Scope.global_)
+statics.add_static('local', Scope.local)
+
+T = Enum('T', 'id key label value')
+statics.add_static('label', T.label)
+statics.add_static('id', T.id)
+statics.add_static('key', T.key)
+statics.add_static('value', T.value)
+
+class P(object):
+   def __init__(self, operator, value, other=None):
+      self.operator = operator
+      self.value = value
+      self.other = other
+   @staticmethod
+   def between(*args):
+      return P("between", *args)
+   @staticmethod
+   def eq(*args):
+      return P("eq", *args)
+   @staticmethod
+   def gt(*args):
+      return P("gt", *args)
+   @staticmethod
+   def gte(*args):
+      return P("gte", *args)
+   @staticmethod
+   def inside(*args):
+      return P("inside", *args)
+   @staticmethod
+   def lt(*args):
+      return P("lt", *args)
+   @staticmethod
+   def lte(*args):
+      return P("lte", *args)
+   @staticmethod
+   def neq(*args):
+      return P("neq", *args)
+   @staticmethod
+   def not_(*args):
+      return P("not", *args)
+   @staticmethod
+   def outside(*args):
+      return P("outside", *args)
+   @staticmethod
+   def test(*args):
+      return P("test", *args)
+   @staticmethod
+   def within(*args):
+      return P("within", *args)
+   @staticmethod
+   def without(*args):
+      return P("without", *args)
+   def and_(self, arg):
+      return P("and", self, arg)
+   def or_(self, arg):
+      return P("or", self, arg)
+   def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
+   def __repr__(self):
+      return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
+
+def between(*args):
+      return P.between(*args)
+statics.add_static('between',between)
+
+def eq(*args):
+      return P.eq(*args)
+statics.add_static('eq',eq)
+
+def gt(*args):
+      return P.gt(*args)
+statics.add_static('gt',gt)
+
+def gte(*args):
+      return P.gte(*args)
+statics.add_static('gte',gte)
+
+def inside(*args):
+      return P.inside(*args)
+statics.add_static('inside',inside)
+
+def lt(*args):
+      return P.lt(*args)
+statics.add_static('lt',lt)
+
+def lte(*args):
+      return P.lte(*args)
+statics.add_static('lte',lte)
+
+def neq(*args):
+      return P.neq(*args)
+statics.add_static('neq',neq)
+
+def not_(*args):
+      return P.not_(*args)
+statics.add_static('not_',not_)
+
+def outside(*args):
+      return P.outside(*args)
+statics.add_static('outside',outside)
+
+def test(*args):
+      return P.test(*args)
+statics.add_static('test',test)
+
+def within(*args):
+      return P.within(*args)
+statics.add_static('within',within)
+
+def without(*args):
+      return P.without(*args)
+statics.add_static('without',without)
+
+
+
+'''
+TRAVERSER
+'''
+
+class Traverser(object):
+    def __init__(self, object, bulk=None):
+        if bulk is None:
+            bulk = statics.long(1)
+        self.object = object
+        self.bulk = bulk
+    def __repr__(self):
+        return str(self.object)
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.object == other.object
+
+'''
+TRAVERSAL SIDE-EFFECTS
+'''
+
+class TraversalSideEffects(object):
+    def keys(self):
+        return set()
+    def get(self, key):
+        raise KeyError(key)
+    def __getitem__(self, key):
+        return self.get(key)
+    def __repr__(self):
+        return "sideEffects[size:" + str(len(self.keys())) + "]"
+
+'''
+TRAVERSAL STRATEGIES
+'''
+
+class TraversalStrategies(object):
+    global_cache = {}
+    def __init__(self, traversal_strategies=None):
+        self.traversal_strategies = traversal_strategies.traversal_strategies if traversal_strategies is not None else []
+    def add_strategies(self, traversal_strategies):
+        self.traversal_strategies = self.traversal_strategies + traversal_strategies
+    async def apply_strategies(self, traversal):
+        for traversal_strategy in self.traversal_strategies:
+            func = traversal_strategy.apply(traversal)
+            if asyncio.iscoroutine(func):
+                await func
+    def __repr__(self):
+        return str(self.traversal_strategies)
+
+
+class TraversalStrategy(object):
+    def __init__(self, strategy_name=None, configuration=None):
+        self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name
+        self.configuration = {} if configuration is None else configuration
+    def apply(self, traversal):
+        return
+    def apply_async(self, traversal):
+        return
+    def __eq__(self, other):
+        return isinstance(other, self.__class__)
+    def __hash__(self):
+        return hash(self.strategy_name)
+    def __repr__(self):
+        return self.strategy_name
+
+'''
+BYTECODE
+'''
+
+class Bytecode(object):
+    def __init__(self, bytecode=None):
+        self.source_instructions = []
+        self.step_instructions = []
+        self.bindings = {}
+        if bytecode is not None:
+            self.source_instructions = list(bytecode.source_instructions)
+            self.step_instructions = list(bytecode.step_instructions)
+    def add_source(self, source_name, *args):
+        instruction = [source_name]
+        for arg in args:
+            instruction.append(self.__convertArgument(arg))
+        self.source_instructions.append(instruction)
+    def add_step(self, step_name, *args):
+        instruction = [step_name]
+        for arg in args:
+            instruction.append(self.__convertArgument(arg))
+        self.step_instructions.append(instruction)
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.source_instructions == other.source_instructions and self.step_instructions == other.step_instructions
+        else:
+            return False
+    def __convertArgument(self,arg):
+        if isinstance(arg, Traversal):
+            self.bindings.update(arg.bytecode.bindings)
+            return arg.bytecode
+        elif isinstance(arg, dict):
+            newDict = {}
+            for key in arg:
+                newDict[self.__convertArgument(key)] = self.__convertArgument(arg[key])
+            return newDict
+        elif isinstance(arg, list):
+            newList = []
+            for item in arg:
+                newList.append(self.__convertArgument(item))
+            return newList
+        elif isinstance(arg, set):
+            newSet = set()
+            for item in arg:
+                newSet.add(self.__convertArgument(item))
+            return newSet
+        elif isinstance(arg, tuple) and 2 == len(arg) and isinstance(arg[0], str):
+            self.bindings[arg[0]] = arg[1]
+            return Binding(arg[0],self.__convertArgument(arg[1]))
+        else:
+            return arg
+    def __repr__(self):
+        return (str(self.source_instructions) if len(self.source_instructions) > 0 else "") + \
+               (str(self.step_instructions) if len(self.step_instructions) > 0 else "")
+
+
+'''
+BINDINGS
+'''
+
+class Bindings(object):
+    def of(self,key,value):
+        if not isinstance(key, str):
+            raise TypeError("Key must be str")
+        return (key,value)
+
+class Binding(object):
+    def __init__(self,key,value):
+        self.key = key
+        self.value = value
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value
+    def __hash__(self):
+        return hash(self.key) + hash(self.value)
+    def __repr__(self):
+        return "binding[" + self.key + "=" + str(self.value) + "]"
diff --git a/aiogremlin/gremlin_python/statics.py b/aiogremlin/gremlin_python/statics.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8ee220005bc01904969c7d802397ddb2eaa3fa3
--- /dev/null
+++ b/aiogremlin/gremlin_python/statics.py
@@ -0,0 +1,57 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+from types import FunctionType
+
+from enum import Enum
+
+
+class long(int): pass
+FloatType = float
+IntType = int
+LongType = long
+TypeType = type
+
+
+staticMethods = {}
+staticEnums = {}
+default_lambda_language = "gremlin-python"
+
+
+def add_static(key, value):
+    if isinstance(value, Enum):
+        staticEnums[key] = value
+    else:
+        staticMethods[key] = value
+
+
+def load_statics(global_dict):
+    for key in staticMethods:
+        global_dict[key] = staticMethods[key]
+    for key in staticEnums:
+        global_dict[key] = staticEnums[key]
+
+
+def unload_statics(global_dict):
+    for key in staticMethods:
+        if key in global_dict:
+            del global_dict[key]
+    for key in staticEnums:
+        if key in global_dict:
+            del global_dict[key]
diff --git a/aiogremlin/gremlin_python/structure/__init__.py b/aiogremlin/gremlin_python/structure/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7626550738f12ccd5e18b8c06a8d68aaab882066
--- /dev/null
+++ b/aiogremlin/gremlin_python/structure/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/aiogremlin/gremlin_python/structure/graph.py b/aiogremlin/gremlin_python/structure/graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7fe22e85d1a32436a14d35742fb5faec4196fd7
--- /dev/null
+++ b/aiogremlin/gremlin_python/structure/graph.py
@@ -0,0 +1,123 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+from aiogremlin.gremlin_python.process.graph_traversal import GraphTraversalSource
+from aiogremlin.gremlin_python.process.traversal import TraversalStrategies
+
+
+class Graph(object):
+    def __init__(self):
+        if self.__class__ not in TraversalStrategies.global_cache:
+            TraversalStrategies.global_cache[self.__class__] = TraversalStrategies()
+
+    def traversal(self):
+        return GraphTraversalSource(
+            self, TraversalStrategies.global_cache[self.__class__])
+
+    def __repr__(self):
+        return "graph[empty]"
+
+
+class Element(object):
+    def __init__(self, id, label):
+        self.id = id
+        self.label = label
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.id == other.id
+
+    def __hash__(self):
+        return hash(self.id)
+
+
+class Vertex(Element):
+    def __init__(self, id, label="vertex"):
+        Element.__init__(self, id, label)
+
+    def __repr__(self):
+        return "v[" + str(self.id) + "]"
+
+
+class Edge(Element):
+    def __init__(self, id, outV, label, inV):
+        Element.__init__(self, id, label)
+        self.outV = outV
+        self.inV = inV
+
+    def __repr__(self):
+        return "e[" + str(self.id) + "][" + str(self.outV.id) + "-" + self.label + "->" + str(self.inV.id) + "]"
+
+
+class VertexProperty(Element):
+    def __init__(self, id, label, value):
+        Element.__init__(self, id, label)
+        self.value = value
+        self.key = self.label
+
+    def __repr__(self):
+        return "vp[" + str(self.label) + "->" + str(self.value)[0:20] + "]"
+
+
+class Property(object):
+    def __init__(self, key, value):
+        self.key = key
+        self.value = value
+
+    def __repr__(self):
+        return "p[" + str(self.key) + "->" + str(self.value)[0:20] + "]"
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value
+
+    def __hash__(self):
+        return hash(self.key) + hash(self.value)
+
+
+class Path(object):
+    def __init__(self, labels, objects):
+        self.labels = labels
+        self.objects = objects
+
+    def __repr__(self):
+        return str(self.objects)
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__) and self.objects == other.objects and self.labels == other.labels
+
+    def __hash__(self):
+        return hash(str(self.objects)) + hash(str(self.labels))
+
+    def __getitem__(self, key):
+        if isinstance(key, str):
+            objects = []
+            for i, labels in enumerate(self.labels):
+                if key in labels:
+                    objects.append(self.objects[i])
+            if 0 == len(objects):
+                raise KeyError("The step with label " + key + " does not exist")
+            return objects if len(objects) > 1 else objects[0]
+        elif isinstance(key, int):
+            return self.objects[key]
+        else:
+            raise TypeError("The path access key must be either a string label or integer index")
+
+    def __len__(self):
+        return len(self.objects)
diff --git a/aiogremlin/gremlin_python/structure/io/__init__.py b/aiogremlin/gremlin_python/structure/io/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7626550738f12ccd5e18b8c06a8d68aaab882066
--- /dev/null
+++ b/aiogremlin/gremlin_python/structure/io/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/aiogremlin/gremlin_python/structure/io/graphson.py b/aiogremlin/gremlin_python/structure/io/graphson.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a29ace617945777d0f6f24948086636bd9a6fda
--- /dev/null
+++ b/aiogremlin/gremlin_python/structure/io/graphson.py
@@ -0,0 +1,341 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+from enum import Enum
+import json
+
+from aiogremlin.gremlin_python import statics
+from aiogremlin.gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType
+from aiogremlin.gremlin_python.process.traversal import Binding, Bytecode, P, Traversal, Traverser, TraversalStrategy
+from aiogremlin.gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path
+
+
+_serializers = {}
+_deserializers = {}
+
+
+class GraphSONTypeType(type):
+    def __new__(mcs, name, bases, dct):
+        cls = super(GraphSONTypeType, mcs).__new__(mcs, name, bases, dct)
+        if not name.startswith('_'):
+            if cls.python_type:
+                _serializers[cls.python_type] = cls
+            if cls.graphson_type:
+                _deserializers[cls.graphson_type] = cls
+        return cls
+
+
+class GraphSONUtil(object):
+    TYPE_KEY = "@type"
+    VALUE_KEY = "@value"
+
+    @classmethod
+    def typedValue(cls, type_name, value, prefix="g"):
+        out = {cls.TYPE_KEY: cls.formatType(prefix, type_name)}
+        if value is not None:
+            out[cls.VALUE_KEY] = value
+        return out
+
+    @classmethod
+    def formatType(cls, prefix, type_name):
+        return "%s:%s" % (prefix, type_name)
+
+# Read/Write classes split to follow precedence of the Java API
+class GraphSONWriter(object):
+
+    def __init__(self, serializer_map=None):
+        """
+        :param serializer_map: map from Python type to serializer instance implementing `dictify`
+        """
+        self.serializers = _serializers.copy()
+        if serializer_map:
+            self.serializers.update(serializer_map)
+
+    def writeObject(self, objectData):
+        # to JSON
+        return json.dumps(self.toDict(objectData), separators=(',', ':'))
+
+    def toDict(self, obj):
+        """
+        Encodes python objects in GraphSON type-tagged dict values
+        """
+        try:
+            return self.serializers[type(obj)].dictify(obj, self)
+        except KeyError:
+            for key, serializer in self.serializers.items():
+                if isinstance(obj, key):
+                    return serializer.dictify(obj, self)
+
+        # list and map are treated as normal json objs (could be isolated serializers)
+        if isinstance(obj, (list, set)):
+            return [self.toDict(o) for o in obj]
+        elif isinstance(obj, dict):
+            return dict((self.toDict(k), self.toDict(v)) for k, v in obj.items())
+        else:
+            return obj
+
+
+class GraphSONReader(object):
+
+    def __init__(self, deserializer_map=None):
+        """
+        :param deserializer_map: map from GraphSON type tag to deserializer instance implementing `objectify`
+        """
+        self.deserializers = _deserializers.copy()
+        if deserializer_map:
+            self.deserializers.update(deserializer_map)
+
+    def readObject(self, jsonData):
+        # from JSON
+        return self.toObject(json.loads(jsonData))
+
+    def toObject(self, obj):
+        """
+        Unpacks GraphSON type-tagged dict values into objects mapped in self.deserializers
+        """
+        if isinstance(obj, dict):
+            try:
+                return self.deserializers[obj[GraphSONUtil.TYPE_KEY]].objectify(obj[GraphSONUtil.VALUE_KEY], self)
+            except KeyError:
+                pass
+            # list and map are treated as normal json objs (could be isolated deserializers)
+            return dict((self.toObject(k), self.toObject(v)) for k, v in obj.items())
+        elif isinstance(obj, list):
+            return [self.toObject(o) for o in obj]
+        else:
+            return obj
+
+
+class _GraphSONTypeIO(metaclass=GraphSONTypeType):
+    python_type = None
+    graphson_type = None
+
+    symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
+                 "or_": "or", "is_": "is", "not_": "not", "from_": "from",
+                 "set_": "set", "list_": "list", "all_": "all"}
+
+    @classmethod
+    def unmangleKeyword(cls, symbol):
+        return cls.symbolMap.get(symbol, symbol)
+
+    def dictify(self, obj, writer):
+        raise NotImplementedError()
+
+    def objectify(self, d, reader):
+        raise NotImplementedError()
+
+
+class _BytecodeSerializer(_GraphSONTypeIO):
+
+    @classmethod
+    def _dictify_instructions(cls, instructions, writer):
+        out = []
+        for instruction in instructions:
+            inst = [instruction[0]]
+            inst.extend(writer.toDict(arg) for arg in instruction[1:])
+            out.append(inst)
+        return out
+
+    @classmethod
+    def dictify(cls, bytecode, writer):
+        if isinstance(bytecode, Traversal):
+            bytecode = bytecode.bytecode
+        out = {}
+        if bytecode.source_instructions:
+            out["source"] = cls._dictify_instructions(bytecode.source_instructions, writer)
+        if bytecode.step_instructions:
+            out["step"] = cls._dictify_instructions(bytecode.step_instructions, writer)
+        return GraphSONUtil.typedValue("Bytecode", out)
+
+
+class TraversalSerializer(_BytecodeSerializer):
+    python_type = Traversal
+
+
+class BytecodeSerializer(_BytecodeSerializer):
+    python_type = Bytecode
+
+
+class TraversalStrategySerializer(_GraphSONTypeIO):
+    python_type = TraversalStrategy
+
+    @classmethod
+    def dictify(cls, strategy, writer):
+        return GraphSONUtil.typedValue(strategy.strategy_name, writer.toDict(strategy.configuration))
+
+
+class TraverserIO(_GraphSONTypeIO):
+    python_type = Traverser
+    graphson_type = "g:Traverser"
+
+    @classmethod
+    def dictify(cls, traverser, writer):
+        return GraphSONUtil.typedValue("Traverser", {"value": writer.toDict(traverser.object),
+                                                     "bulk": writer.toDict(traverser.bulk)})
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Traverser(reader.toObject(d["value"]),
+                         reader.toObject(d["bulk"]))
+
+
+class EnumSerializer(_GraphSONTypeIO):
+    python_type = Enum
+
+    @classmethod
+    def dictify(cls, enum, _):
+        return GraphSONUtil.typedValue(cls.unmangleKeyword(type(enum).__name__),
+                                       cls.unmangleKeyword(str(enum.name)))
+
+
+class PSerializer(_GraphSONTypeIO):
+    python_type = P
+
+    @classmethod
+    def dictify(cls, p, writer):
+        out = {"predicate": p.operator,
+               "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
+                        writer.toDict(p.value)}
+        return GraphSONUtil.typedValue("P", out)
+
+
+class BindingSerializer(_GraphSONTypeIO):
+    python_type = Binding
+
+    @classmethod
+    def dictify(cls, binding, writer):
+        out = {"key": binding.key,
+               "value": writer.toDict(binding.value)}
+        return GraphSONUtil.typedValue("Binding", out)
+
+
+class LambdaSerializer(_GraphSONTypeIO):
+    python_type = FunctionType
+
+    @classmethod
+    def dictify(cls, lambda_object, writer):
+        lambda_result = lambda_object()
+        script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
+        language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
+        out = {"script": script,
+               "language": language}
+        if language == "gremlin-jython" or language == "gremlin-python":
+            if not script.strip().startswith("lambda"):
+                script = "lambda " + script
+                out["script"] = script
+            out["arguments"] = eval(out["script"]).__code__.co_argcount
+        else:
+            out["arguments"] = -1
+        return GraphSONUtil.typedValue("Lambda", out)
+
+
+class TypeSerializer(_GraphSONTypeIO):
+    python_type = TypeType
+
+    @classmethod
+    def dictify(cls, typ, writer):
+        return writer.toDict(typ())
+
+
+class _NumberIO(_GraphSONTypeIO):
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):  # because isinstance(False, int) and isinstance(True, int)
+            return n
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+    @classmethod
+    def objectify(cls, v, _):
+        return cls.python_type(v)
+
+
+class FloatIO(_NumberIO):
+    python_type = FloatType
+    graphson_type = "g:Float"
+    graphson_base_type = "Float"
+
+
+class DoubleIO(FloatIO):
+    graphson_type = "g:Double"
+    graphson_base_type = "Double"
+
+
+class Int64IO(_NumberIO):
+    python_type = LongType
+    graphson_type = "g:Int64"
+    graphson_base_type = "Int64"
+
+
+class Int32IO(_NumberIO):
+    python_type = IntType
+    graphson_type = "g:Int32"
+    graphson_base_type = "Int32"
+
+    @classmethod
+    def dictify(cls, n, writer):
+        if isinstance(n, bool):
+            return n
+        return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+
+class VertexDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Vertex"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Vertex(reader.toObject(d["id"]), d.get("label", ""))
+
+
+class EdgeDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Edge"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Edge(reader.toObject(d["id"]),
+                    Vertex(reader.toObject(d["outV"]), ""),
+                    d.get("label", "vertex"),
+                    Vertex(reader.toObject(d["inV"]), ""))
+
+
+class VertexPropertyDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:VertexProperty"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return VertexProperty(reader.toObject(d["id"]), d["label"],
+                              reader.toObject(d["value"]))
+
+
+class PropertyDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Property"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        return Property(d["key"], reader.toObject(d["value"]))
+
+
+class PathDeserializer(_GraphSONTypeIO):
+    graphson_type = "g:Path"
+
+    @classmethod
+    def objectify(cls, d, reader):
+        labels = [set(label) for label in d["labels"]]
+        objects = [reader.toObject(o) for o in d["objects"]]
+        return Path(labels, objects)
diff --git a/aiogremlin/remote/__init__.py b/aiogremlin/remote/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/aiogremlin/remote/driver_remote_connection.py b/aiogremlin/remote/driver_remote_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..60531b4bbf42d38dfc4d8138e59bfbea4ac6b41e
--- /dev/null
+++ b/aiogremlin/remote/driver_remote_connection.py
@@ -0,0 +1,64 @@
+import asyncio
+from urllib.parse import urlparse
+
+from aiogremlin.driver.cluster import Cluster
+from aiogremlin.gremlin_python.driver import serializer
+from aiogremlin.remote.driver_remote_side_effects import RemoteTraversalSideEffects
+from aiogremlin.gremlin_python.driver.remote_connection import RemoteTraversal
+
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+class DriverRemoteConnection:
+
+    def __init__(self, client, loop, *, cluster=None):
+        self._client = client
+        self._loop = loop
+        self._cluster = cluster
+
+    @property
+    def client(self):
+        return self._client
+
+    @property
+    def config(self):
+        return self._cluster.config
+
+    @classmethod
+    async def using(cls, cluster, aliases=None, *, loop=None):
+        client = await cluster.connect(aliases=aliases)
+        if not loop:
+            loop = asyncio.get_event_loop()
+        return cls(client, loop)
+
+    @classmethod
+    async def open(cls, url=None, aliases=None, loop=None, *,
+                   graphson_reader=None, graphson_writer=None, **config):
+        if url:
+            parsed_url = urlparse(url)
+            config.update({
+                'scheme': parsed_url.scheme,
+                'hosts': [parsed_url.hostname],
+                'port': parsed_url.port})
+        if isinstance(aliases, str):
+            aliases = {'g': aliases}
+        if not loop:
+            loop = asyncio.get_event_loop()
+        message_serializer = serializer.GraphSONMessageSerializer(
+            reader=graphson_reader,
+            writer=graphson_writer)
+        config.update({'message_serializer': message_serializer})
+        cluster = await Cluster.open(loop, aliases=aliases, **config)
+        client = await cluster.connect()
+        return cls(client, loop, cluster=cluster)
+
+    async def close(self):
+        if self._cluster:
+            await self._cluster.close()
+
+    async def submit(self, bytecode):
+        result_set = await self._client.submit(bytecode)
+        side_effects = RemoteTraversalSideEffects(result_set.request_id,
+                                                  self._client)
+        return RemoteTraversal(result_set, side_effects)
diff --git a/aiogremlin/remote/driver_remote_side_effects.py b/aiogremlin/remote/driver_remote_side_effects.py
new file mode 100644
index 0000000000000000000000000000000000000000..9dc59c7c82e7603f11a15a748e90268ac833eb14
--- /dev/null
+++ b/aiogremlin/remote/driver_remote_side_effects.py
@@ -0,0 +1,84 @@
+from aiogremlin.gremlin_python.driver import request
+from aiogremlin.gremlin_python.process import traversal
+
+
+
+class RemoteTraversalSideEffects(traversal.TraversalSideEffects):
+    def __init__(self, side_effect, client):
+        self._side_effect = side_effect
+        self._client = client
+        self._keys = set()
+        self._side_effects = {}
+        self._closed = False
+
+    async def __getitem__(self, key):
+        if isinstance(key, slice):
+            raise TypeError(
+                'RemoteTraversalSideEffects does not support slicing')
+        return await self.get(key)
+
+    async def keys(self):
+        if not self._closed:
+            message = request.RequestMessage(
+                'traversal', 'keys',
+                {'sideEffect': self._side_effect,
+                'aliases': self._client.aliases})
+            result_set = await self._client.submit(message)
+            results = await result_set.all()
+            self._keys = set(results)
+        return self._keys
+
+    async def get(self, key):
+        if not self._side_effects.get(key):
+            if not self._closed:
+                results = await self._get(key)
+                self._side_effects[key] = results
+                self._keys.add(key)
+            else:
+                return None
+        return self._side_effects[key]
+
+    async def _get(self, key):
+        message = request.RequestMessage(
+            'traversal', 'gather',
+            {'sideEffect': self._side_effect, 'sideEffectKey': key,
+             'aliases': self._client.aliases})
+        result_set = await self._client.submit(message)
+        return await self._aggregate_results(result_set)
+
+    async def close(self):
+        if not self._closed:
+            message = request.RequestMessage(
+                'traversal', 'close',
+                {'sideEffect': self._side_effect,
+                 'aliases': {'g': self._client.aliases}})
+            result_set = await self._client.submit(message)
+        self._closed = True
+        return await result_set.one()
+
+    async def _aggregate_results(self, result_set):
+        aggregates = {'list': [], 'set': set(), 'map': {}, 'bulkset': {},
+                      'none': None}
+        results = None
+        async for msg in result_set:
+            if results is None:
+                aggregate_to = result_set.aggregate_to
+                results = aggregates.get(aggregate_to, [])
+            # on first message, get the right result data structure
+            # if there is no update to a structure, then the item is the result
+            if results is None:
+                results = msg
+            # updating a map is different than a list or a set
+            elif isinstance(results, dict):
+                if aggregate_to == "map":
+                    results.update(msg)
+                else:
+                    results[msg.object] = msg.bulk
+            elif isinstance(results, set):
+                results.update(msg)
+            # flat add list to result list
+            else:
+                results.append(msg)
+        if results is None:
+            results = []
+        return results
diff --git a/aiogremlin/response.py b/aiogremlin/response.py
deleted file mode 100644
index fedf9d8af50806ef04d9e75981bf133e2efb1b20..0000000000000000000000000000000000000000
--- a/aiogremlin/response.py
+++ /dev/null
@@ -1,116 +0,0 @@
-"""
-Class used to pass messages with the Gremlin Server.
-"""
-
-import asyncio
-import base64
-import hashlib
-import os
-
-import aiohttp
-
-from aiowebsocketclient.connector import ClientWebSocketResponse
-
-__all__ = ('GremlinClientWebSocketResponse',)
-
-
-class GremlinClientWebSocketResponse(ClientWebSocketResponse):
-    """Wraps :py:class:`aiohttp.websocket_client.ClientWebSocketResponse`
-    with minimal added functionality for the Gremln Server use case.
-    """
-    def __init__(self, reader, writer, protocol, response, timeout, autoclose,
-                 autoping, loop):
-        ClientWebSocketResponse.__init__(self, reader, writer, protocol,
-                                         response, timeout, autoclose,
-                                         autoping, loop)
-        self._parser = aiohttp.StreamParser(buf=aiohttp.DataQueue(loop=loop),
-                                            loop=loop)
-
-    @property
-    def parser(self):
-        """
-        Read-only property.
-
-        :returns: :py:class:`aiohttp.parsers.StreamParser`
-        """
-        return self._parser
-
-    @asyncio.coroutine
-    def _close(self, *, code=1000, message=b''):
-        if not self._closed:
-            did_close = self._do_close()
-            if did_close:
-                return True
-            while True:
-                try:
-                    msg = yield from asyncio.wait_for(
-                        self._reader.read(), self._timeout, loop=self._loop)
-                except asyncio.CancelledError:
-                    self._close_code = 1006
-                    self._response.close(force=True)
-                    raise
-                except Exception as exc:
-                    self._close_code = 1006
-                    self._exception = exc
-                    self._response.close(force=True)
-                    return True
-
-                if msg.tp == aiohttp.MsgType.close:
-                    self._close_code = msg.data
-                    self._response.close(force=True)
-                    return True
-        else:
-            return False
-
-    def _do_close(self, code=1000, message=b''):
-        self._closed = True
-        try:
-            self._writer.close(code, message)
-        except asyncio.CancelledError:
-            self._close_code = 1006
-            self._response.close(force=True)
-            raise
-        except Exception as exc:
-            self._close_code = 1006
-            self._exception = exc
-            self._response.close(force=True)
-            return True
-
-        if self._closing:
-            self._response.close(force=True)
-            return True
-
-    def send(self, message, *, binary=True):
-        """Send a message to the server."""
-        if binary:
-            method = self.send_bytes
-        else:
-            method = self.send_str
-        try:
-            method(message)
-        except RuntimeError:
-            # Socket closed.
-            raise
-        except TypeError:
-            # Bytes/string input error.
-            raise
-
-    @asyncio.coroutine
-    def receive(self):
-        """
-        :ref:`coroutine<coroutine>` method
-
-        Receive a message from the server and push it into the parser.
-        """
-        msg = yield from super().receive()
-        if msg.tp == aiohttp.MsgType.binary:
-            self.parser.feed_data(msg.data.decode())
-        elif msg.tp == aiohttp.MsgType.text:
-            self.parser.feed_data(msg.data.strip())
-        else:
-            if msg.tp == aiohttp.MsgType.close:
-                yield from ws.close()
-            elif msg.tp == aiohttp.MsgType.error:
-                raise msg.data
-            elif msg.tp == aiohttp.MsgType.closed:
-                pass
diff --git a/aiogremlin/subprotocol.py b/aiogremlin/subprotocol.py
deleted file mode 100644
index e75f55e048693df498a68b9605f3ffc6b03d692a..0000000000000000000000000000000000000000
--- a/aiogremlin/subprotocol.py
+++ /dev/null
@@ -1,121 +0,0 @@
-"""Implements the Gremlin Server subprotocol."""
-
-import base64
-import collections
-import uuid
-
-try:
-    import ujson as json
-except ImportError:
-    import json
-
-from aiogremlin.exceptions import RequestError, GremlinServerError
-
-__all__ = ("GremlinWriter", "gremlin_response_parser", "Message")
-
-
-Message = collections.namedtuple(
-    "Message",
-    ["status_code", "data", "message", "metadata"])
-
-
-def gremlin_response_parser(out, buf):
-    while True:
-        message = yield
-        message = json.loads(message)
-        message = Message(message["status"]["code"],
-                          message["result"]["data"],
-                          message["status"]["message"],
-                          message["result"]["meta"])
-        if message.status_code == 200:
-            out.feed_data(message)
-            out.feed_eof()
-        elif message.status_code == 206 or message.status_code == 407:
-            out.feed_data(message)
-        elif message.status_code == 204:
-            out.feed_data(message)
-            out.feed_eof()
-        else:
-            if message.status_code < 500:
-                raise RequestError(message.status_code, message.message)
-            else:
-                raise GremlinServerError(message.status_code, message.message)
-
-
-class GremlinWriter:
-
-    def __init__(self, ws):
-        self.ws = ws
-
-    def write(self, *, gremlin="", bindings=None, lang="gremlin-groovy",
-              rebindings=None, op="eval", processor="", session=None,
-              binary=True, mime_type="application/json", username="",
-              password=""):
-        if rebindings is None:
-            rebindings = {}
-        if op == "eval":
-            message = self._prepare_message(gremlin,
-                                            bindings,
-                                            lang,
-                                            rebindings,
-                                            op,
-                                            processor,
-                                            session)
-
-        if op == "authentication":
-            message = self._authenticate(
-                username, password, session, processor)
-        message = json.dumps(message)
-        if binary:
-            message = self._set_message_header(message, mime_type)
-        self.ws.send(message, binary=binary)
-        return self.ws
-
-    @staticmethod
-    def _set_message_header(message, mime_type):
-        if mime_type == "application/json":
-            mime_len = b"\x10"
-            mime_type = b"application/json"
-        else:
-            raise ValueError("Unknown mime type.")
-        return b"".join([mime_len, mime_type, bytes(message, "utf-8")])
-
-    @staticmethod
-    def _prepare_message(gremlin, bindings, lang, rebindings, op, processor,
-                         session):
-        message = {
-            "requestId": str(uuid.uuid4()),
-            "op": op,
-            "processor": processor,
-            "args": {
-                "gremlin": gremlin,
-                "bindings": bindings,
-                "language":  lang,
-                "rebindings": rebindings
-            }
-        }
-        if session is None:
-            if processor == "session":
-                raise RuntimeError("session processor requires a session id")
-        else:
-            message["args"].update({"session": session})
-        return message
-
-
-    @staticmethod
-    def _authenticate(username, password, session, processor):
-        auth = b"".join([b"\x00", bytes(username, "utf-8"), b"\x00", bytes(password, "utf-8")])
-        message = {
-            "requestId": str(uuid.uuid4()),
-            "op": "authentication",
-            "processor": processor,
-            "args": {
-                "sasl": base64.b64encode(auth).decode()
-            }
-        }
-        if session is None:
-            if processor == "session":
-                raise RuntimeError("session processor requires a session id")
-        else:
-            message["args"].update({"session": session})
-        return message
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..cfcbfea95cdd0b95dd262f7a44e723e8df284400
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[aliases]
+test=pytest
+
+[tool:pytest]
+norecursedirs = '.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg' lib lib64
diff --git a/setup.py b/setup.py
index 78cd7c4b25fa282326c45ab8b34f15c9c4f4b9f5..a041ad2d86b1fd0f5548815b51140f29d2b2f198 100644
--- a/setup.py
+++ b/setup.py
@@ -2,20 +2,27 @@ from setuptools import setup
 
 
 setup(
-    name="aiogremlin",
-    version="0.1.3",
-    url="",
-    license="MIT",
-    author="davebshow",
-    author_email="davebshow@gmail.com",
-    description="Python 3 driver for TP3 Gremlin Server built on Asyncio and aiohttp",
-    long_description=open("README.txt").read(),
-    packages=["aiogremlin", "tests"],
+    name='aiogremlin',
+    version='3.2.4',
+    url='',
+    license='MIT',
+    author='davebshow',
+    author_email='davebshow@gmail.com',
+    description='Async Gremlin-Python',
+    long_description=open('README.txt').read(),
+    packages=['aiogremlin', 'aiogremlin.driver', 'aiogremlin.driver.aiohttp',
+              'aiogremlin.gremlin_python', 'aiogremlin.gremlin_python.driver',
+              'aiogremlin.gremlin_python.process',
+              'aiogremlin.gremlin_python.structure',
+              'aiogremlin.gremlin_python.structure.io',
+              'aiogremlin.remote'],
     install_requires=[
-        "aiohttp==0.18.4",
-        "aiowebsocketclient==0.0.5"
+        'aiohttp==1.3.3',
+        'PyYAML==3.12'
     ],
-    test_suite="tests",
+    test_suite='tests',
+    setup_requires=['pytest-runner'],
+    tests_require=['pytest-asyncio', 'pytest', 'mock'],
     classifiers=[
         'Development Status :: 3 - Alpha',
         'Intended Audience :: Developers',
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e4bafe5e06b56f3dc57fdfc30682aabc2246659b..0000000000000000000000000000000000000000
--- a/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-import tests
diff --git a/tests/config/config.json b/tests/config/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..025136e47ae4f118856f1ed97ac8e612878916a7
--- /dev/null
+++ b/tests/config/config.json
@@ -0,0 +1,13 @@
+{
+   "ssl_password":"",
+   "port":8182,
+   "ssl_certfile":"",
+   "scheme":"wss",
+   "hosts":[
+      "localhost"
+   ],
+   "username":"dave",
+   "password":"mypass",
+   "ssl_keyfile":"",
+   "message_serializer":"aiogremlin.gremlin_python.driver.serializer.GraphSONMessageSerializer"
+}
diff --git a/tests/config/config.yml b/tests/config/config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5762be39a72c7ca94771c1d6076985d166018c96
--- /dev/null
+++ b/tests/config/config.yml
@@ -0,0 +1,4 @@
+scheme: 'wss'
+hosts: ['localhost']
+port: 8183
+message_serializer: 'aiogremlin.gremlin_python.driver.serializer.GraphSONMessageSerializer'
diff --git a/tests/config_module.py b/tests/config_module.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd609ccd281927c45873f8211aaea63b493566d1
--- /dev/null
+++ b/tests/config_module.py
@@ -0,0 +1,4 @@
+SCHEME = 'wss'
+HOSTS = ['localhost']
+PORT = 8183
+MESSAGE_SERIALIZER = 'aiogremlin.gremlin_python.driver.serializer.GraphSONMessageSerializer'
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e860e0b35b9e88e0666d9d8d7484ba5cc420a0e
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,135 @@
+# Copyright 2016 David M. Brown
+#
+# This file is part of Goblin.
+#
+# Goblin is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Goblin is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
+import asyncio
+import pytest
+from aiogremlin import driver
+from aiogremlin.driver.provider import TinkerGraph
+from aiogremlin.gremlin_python.driver import serializer
+
+
+# def pytest_generate_tests(metafunc):
+#     if 'cluster' in metafunc.fixturenames:
+#         metafunc.parametrize("cluster", ['c1', 'c2'], indirect=True)
+
+
+def pytest_addoption(parser):
+    parser.addoption('--provider', default='tinkergraph',
+                     choices=('tinkergraph', 'dse',))
+    parser.addoption('--gremlin-host', default='localhost')
+    parser.addoption('--gremlin-port', default='8182')
+
+
+@pytest.fixture
+def provider(request):
+    provider = request.config.getoption('provider')
+    if provider == 'tinkergraph':
+        return TinkerGraph
+    elif provider == 'dse':
+        try:
+            import goblin_dse
+        except ImportError:
+            raise RuntimeError("Couldn't run tests with DSEGraph provider: the goblin_dse package "
+                               "must be installed")
+        else:
+            return goblin_dse.DSEGraph
+
+
+@pytest.fixture
+def aliases(request):
+    if request.config.getoption('provider') == 'tinkergraph':
+        return {'g': 'g'}
+    elif request.config.getoption('provider') == 'dse':
+        return {'g': 'testgraph.g'}
+
+
+@pytest.fixture
+def gremlin_server():
+    return driver.GremlinServer
+
+
+@pytest.fixture
+def unused_server_url(unused_tcp_port):
+    return 'http://localhost:{}/gremlin'.format(unused_tcp_port)
+
+
+@pytest.fixture
+def gremlin_host(request):
+    return request.config.getoption('gremlin_host')
+
+
+@pytest.fixture
+def gremlin_port(request):
+    return request.config.getoption('gremlin_port')
+
+
+@pytest.fixture
+def gremlin_url(gremlin_host, gremlin_port):
+    return "http://{}:{}/gremlin".format(gremlin_host, gremlin_port)
+
+
+@pytest.fixture
+def connection(gremlin_url, event_loop, provider):
+    try:
+        conn = event_loop.run_until_complete(
+            driver.Connection.open(
+                gremlin_url, event_loop,
+                message_serializer=serializer.GraphSONMessageSerializer,
+                provider=provider
+            ))
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    return conn
+
+
+@pytest.fixture
+def connection_pool(gremlin_url, event_loop, provider):
+    return driver.ConnectionPool(
+        gremlin_url, event_loop, None, '', '', 4, 1, 16,
+        64, None, serializer.GraphSONMessageSerializer, provider=provider)
+
+
+@pytest.fixture
+def cluster(request, gremlin_host, gremlin_port, event_loop, provider, aliases):
+    # if request.param == 'c1':
+    cluster = driver.Cluster(
+        event_loop,
+        hosts=[gremlin_host],
+        port=gremlin_port,
+        aliases=aliases,
+        message_serializer=serializer.GraphSONMessageSerializer,
+        provider=provider
+    )
+    # elif request.param == 'c2':
+    #     cluster = driver.Cluster(
+    #         event_loop,
+    #         hosts=[gremlin_host],
+    #         port=gremlin_port,
+    #         aliases=aliases,
+    #         message_serializer=serializer.GraphSONMessageSerializer,
+    #         provider=provider
+    #     )
+    return cluster
+
+# TOOO FIX
+# @pytest.fixture
+# def remote_graph():
+#      return driver.AsyncGraph()
+
+# Class fixtures
+@pytest.fixture
+def cluster_class(event_loop):
+    return driver.Cluster
diff --git a/tests/test_client.py b/tests/test_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf9aacde9766d4d5fc3c4ecc04142058b1c066f9
--- /dev/null
+++ b/tests/test_client.py
@@ -0,0 +1,64 @@
+# Copyright 2016 David M. Brown
+#
+# This file is part of Goblin.
+#
+# Goblin is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Goblin is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
+
+import asyncio
+import uuid
+
+import pytest
+
+from aiogremlin.driver.server import GremlinServer
+
+
+@pytest.mark.asyncio
+async def test_client_auto_release(cluster):
+    client = await cluster.connect()
+    resp = await client.submit("1 + 1")
+    async for msg in resp:
+        pass
+    await asyncio.sleep(0)
+    host = cluster._hosts.popleft()
+    assert len(host._pool._available) == 1
+    await host.close()
+
+
+@pytest.mark.asyncio
+async def test_alias(cluster):
+    client = await cluster.connect()
+    aliased_client = client.alias({"g": "g1"})
+    assert aliased_client._aliases == {"g": "g1"}
+    assert aliased_client._cluster is client._cluster
+    assert aliased_client._loop is client._loop
+    await cluster.close()
+
+
+# @pytest.mark.asyncio
+# async def test_sessioned_client(cluster):
+#     session = str(uuid.uuid4())
+#     client = await cluster.connect(session=session)
+#     assert isinstance(client.cluster, GremlinServer)
+#     resp = await client.submit(gremlin="v = g.addV('person').property('name', 'joe').next(); v")
+#     async for msg in resp:
+#         try:
+#             assert msg['properties']['name'][0]['value'] == 'joe'
+#         except KeyError:
+#             assert msg['properties']['name'][0]['@value']['value'] == 'joe'
+#
+#     resp = await client.submit(gremlin="g.V(v.id()).values('name')")
+#
+#     async for msg in resp:
+#         assert msg == 'joe'
+#     await cluster.close()
diff --git a/tests/test_config.py b/tests/test_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..e4bdee3b2db19d4954fd8bb275da4bf679075c82
--- /dev/null
+++ b/tests/test_config.py
@@ -0,0 +1,102 @@
+# Copyright 2016 David M. Brown
+#
+# This file is part of Goblin.
+#
+# Goblin is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Goblin is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
+import os
+
+import pytest
+
+from aiogremlin import driver, exception
+from aiogremlin.gremlin_python.driver import serializer
+
+import config_module
+
+
+dirname = os.path.dirname(os.path.dirname(__file__))
+
+
+@pytest.fixture(params=[0, 1])
+def conf_module(request):
+    if request.param:
+        return 'config_module'
+    else:
+        return config_module
+
+
+def test_cluster_default_config(event_loop):
+    cluster = driver.Cluster(event_loop)
+    assert cluster.config['scheme'] == 'ws'
+    assert cluster.config['hosts'] == ['localhost']
+    assert cluster.config['port'] == 8182
+    assert cluster.config['ssl_certfile'] == ''
+    assert cluster.config['ssl_keyfile'] == ''
+    assert cluster.config['ssl_password'] == ''
+    assert cluster.config['username'] == ''
+    assert cluster.config['password'] == ''
+
+
+def test_cluster_custom_config(event_loop, cluster_class):
+    cluster = cluster_class(event_loop, username='dave', password='mypass',
+                            hosts=['127.0.0.1'])
+    assert cluster.config['scheme'] == 'ws'
+    assert cluster.config['hosts'] == ['127.0.0.1']
+    assert cluster.config['port'] == 8182
+    assert cluster.config['ssl_certfile'] == ''
+    assert cluster.config['ssl_keyfile'] == ''
+    assert cluster.config['ssl_password'] == ''
+    assert cluster.config['username'] == 'dave'
+    assert cluster.config['password'] == 'mypass'
+    assert issubclass(cluster.config['message_serializer'],
+                      serializer.GraphSONMessageSerializer)
+
+
+def test_cluster_config_from_json(event_loop, cluster_class):
+    cluster = cluster_class(event_loop)
+    cluster.config_from_file(dirname + '/tests/config/config.json')
+    assert cluster.config['scheme'] == 'wss'
+    assert cluster.config['hosts'] == ['localhost']
+    assert cluster.config['port'] == 8182
+    assert cluster.config['ssl_certfile'] == ''
+    assert cluster.config['ssl_keyfile'] == ''
+    assert cluster.config['ssl_password'] == ''
+    assert cluster.config['username'] == 'dave'
+    assert cluster.config['password'] == 'mypass'
+
+    assert issubclass(cluster.config['message_serializer'],
+                      serializer.GraphSONMessageSerializer)
+
+
+def test_cluster_config_from_yaml(event_loop, cluster_class):
+    cluster = cluster_class(event_loop)
+    cluster.config_from_file(dirname + '/tests/config/config.yml')
+    assert cluster.config['scheme'] == 'wss'
+    assert cluster.config['hosts'] == ['localhost']
+    assert cluster.config['port'] == 8183
+    assert cluster.config['ssl_certfile'] == ''
+    assert cluster.config['ssl_keyfile'] == ''
+    assert cluster.config['ssl_password'] == ''
+    assert cluster.config['username'] == ''
+    assert cluster.config['password'] == ''
+    assert issubclass(cluster.config['message_serializer'],
+                      serializer.GraphSONMessageSerializer)
+
+
+def test_cluster_config_from_module(event_loop, cluster_class, conf_module):
+    cluster = cluster_class(event_loop)
+    cluster.config_from_module(conf_module)
+    assert cluster.config['scheme'] == 'wss'
+    assert cluster.config['hosts'] == ['localhost']
+    assert cluster.config['port'] == 8183
+    assert cluster.config['message_serializer'] is serializer.GraphSONMessageSerializer
diff --git a/tests/test_connection.py b/tests/test_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7b557a6a2b2b32013d4193a47d7f330d48f220e
--- /dev/null
+++ b/tests/test_connection.py
@@ -0,0 +1,183 @@
+# Copyright 2016 David M. Brown
+#
+# This file is part of Goblin.
+#
+# Goblin is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Goblin is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
+import asyncio
+import json
+
+import base64
+import pytest
+
+import aiohttp
+from aiohttp import web
+
+from aiogremlin import driver
+from aiogremlin import exception
+from aiogremlin.driver import provider
+from aiogremlin.gremlin_python.driver import request, serializer
+
+
+@pytest.mark.asyncio
+async def test_get_close_conn(connection):
+    ws = connection._transport
+    assert not ws.closed
+    assert not connection.closed
+    await connection.close()
+    assert connection.closed
+    assert ws.closed
+
+
+@pytest.mark.asyncio
+async def test_conn_context_manager(connection):
+    async with connection:
+        assert not connection.closed
+    assert connection.closed
+
+
+@pytest.mark.asyncio
+async def test_submit(connection):
+    async with connection:
+        message = request.RequestMessage(
+            processor='', op='eval',
+            args={'gremlin': '1 + 1'})
+        stream = await connection.submit(message)
+        results = []
+        async for msg in stream:
+            results.append(msg)
+        assert len(results) == 1
+        assert results[0] == 2
+
+
+@pytest.mark.asyncio
+async def test_204_empty_stream(connection):
+    resp = False
+    async with connection:
+        message = request.RequestMessage(
+            processor='', op='eval',
+            args={'gremlin': 'g.V().has("unlikely", "even less likely")'})
+        stream = await connection.submit(message)
+        async for msg in stream:
+            resp = True
+    assert not resp
+
+
+@pytest.mark.asyncio
+async def test_server_error(connection):
+    async with connection:
+        message = request.RequestMessage(
+            processor='', op='eval',
+            args={'gremlin': 'g. V jla;sdf'})
+        stream = await connection.submit(message)
+        with pytest.raises(exception.GremlinServerError):
+            async for msg in stream:
+                pass
+
+
+@pytest.mark.asyncio
+async def test_cant_connect(event_loop, gremlin_server, unused_server_url):
+    with pytest.raises(Exception):
+        await gremlin_server.get_connection(unused_server_url, event_loop)
+
+
+@pytest.mark.asyncio
+async def test_resp_queue_removed_from_conn(connection):
+    async with connection:
+        message = request.RequestMessage(
+            processor='', op='eval',
+            args={'gremlin': '1 + 1'})
+        stream = await connection.submit(message)
+        async for msg in stream:
+            pass
+        await asyncio.sleep(0)
+        assert stream not in list(connection._result_sets.values())
+
+
+@pytest.mark.asyncio
+async def test_stream_done(connection):
+    async with connection:
+        message = request.RequestMessage(
+            processor='', op='eval',
+            args={'gremlin': '1 + 1'})
+        stream = await connection.submit(message)
+        async for msg in stream:
+            pass
+        assert stream.done
+
+@pytest.mark.asyncio
+async def test_connection_response_timeout(connection):
+    async with connection:
+        connection._response_timeout = 0.0000001
+        with pytest.raises(exception.ResponseTimeoutError):
+            message = request.RequestMessage(
+                processor='', op='eval',
+                args={'gremlin': '1 + 1'})
+            stream = await connection.submit(message)
+            async for msg in stream:
+                pass
+
+
+# @pytest.mark.asyncio
+# async def test_authenticated_connection(event_loop, unused_tcp_port):
+#     authentication_request_queue = asyncio.Queue(loop=event_loop)
+#
+#     username, password = 'test_username', 'test_password'
+#
+#     async def fake_auth(request):
+#         ws = web.WebSocketResponse()
+#         await ws.prepare(request)
+#
+#         msg = await ws.receive()
+#         data = json.loads(msg.data.decode()[17:])
+#         await authentication_request_queue.put(data)
+#
+#         auth_resp = {
+#             "requestId": data["requestId"],
+#             "status": {"code": 407, "attributes": {}, "message": ""},
+#             "result": {"data": None, "meta": {}}
+#         }
+#         resp_payload = json.dumps(auth_resp)
+#         ws.send_str(resp_payload)
+#
+#         auth_msg = await ws.receive()
+#         auth_msg_data = json.loads(auth_msg.data.decode()[17:])
+#         await authentication_request_queue.put(auth_msg_data)
+#
+#         return ws
+#
+#     aiohttp_app = web.Application(loop=event_loop)
+#     aiohttp_app.router.add_route('GET', '/gremlin', fake_auth)
+#     handler = aiohttp_app.make_handler()
+#     srv = await event_loop.create_server(handler, '0.0.0.0', unused_tcp_port)
+#
+#     async with aiohttp.ClientSession(loop=event_loop) as session:
+#         url = 'ws://0.0.0.0:{}/gremlin'.format(unused_tcp_port)
+#         async with session.ws_connect(url) as ws_client:
+#             connection = driver.Connection(
+#                 url=url, ws=ws_client, loop=event_loop, client_session=session,
+#                 username=username, password=password, max_inflight=64, response_timeout=None,
+#                 message_serializer=serializer.GraphSONMessageSerializer,
+#                 provider=provider.TinkerGraph
+#             )
+#             task = event_loop.create_task(connection.submit("1+1"))
+#             initial_request = await authentication_request_queue.get()
+#             auth_request = await authentication_request_queue.get()
+#             print(auth_request)
+#             auth_str = auth_request['args']['sasl']
+#             assert base64.b64decode(auth_str).decode().split('\x00')[1:] == [username, password]
+#             assert auth_request['requestId'] == initial_request['requestId']
+#             resp = await task
+#             resp.close()
+#
+#             await connection.close()
diff --git a/tests/test_connection_protocol.py b/tests/test_connection_protocol.py
new file mode 100644
index 0000000000000000000000000000000000000000..96420128e6975db721ed3469150cdd9a4fb3f3c3
--- /dev/null
+++ b/tests/test_connection_protocol.py
@@ -0,0 +1,152 @@
+# # Copyright 2016 David M. Brown
+# #
+# # This file is part of Goblin.
+# #
+# # Goblin is free software: you can redistribute it and/or modify
+# # it under the terms of the GNU Affero General Public License as published by
+# # the Free Software Foundation, either version 3 of the License, or
+# # (at your option) any later version.
+# #
+# # Goblin is distributed in the hope that it will be useful,
+# # but WITHOUT ANY WARRANTY; without even the implied warranty of
+# # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# # GNU Affero General Public License for more details.
+# #
+# # You should have received a copy of the GNU Affero General Public License
+# # along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
+#
+# import asyncio
+# import uuid
+# import pytest
+#
+# from aiogremlin import exception
+# from aiogremlin.gremlin_python.driver import request, serializer
+#
+#
+# @pytest.mark.asyncio
+# async def test_eval(remote_graph, connection, aliases):
+#     async with connection:
+#         connection._message_serializer = serializer.GraphSONMessageSerializer()
+#         g = remote_graph.traversal()
+#         traversal = "g.addV('person').property('name', 'leifur')"
+#         message = request.RequestMessage(
+#             processor='', op='eval',
+#             args={'gremlin': message,
+#                   'aliases': aliases})
+#         resp = await connection.submit(
+#             processor='', op='eval', gremlin=traversal, scriptEvalTimeout=1, aliases=aliases)
+#
+#         async for msg in resp:
+#             assert msg['label'] == 'person'
+#
+#
+# @pytest.mark.asyncio
+# async def test_bytecode(remote_graph, connection, aliases):
+#     async with connection:
+#         connection._message_serializer = serializer.GraphSONMessageSerializer()
+#         g = remote_graph.traversal()
+#         traversal = g.addV('person').property('name', 'leifur')
+#         message = request.RequestMessage(
+#             processor='traversal', op='bytecode',
+#             args={'gremlin': traversal.bytecode,
+#                   'aliases': aliases})
+#         resp = await connection.submit(message)
+#         async for msg in resp:
+#             vid = msg.id
+#         traversal = g.V(vid).label()
+#         message = request.RequestMessage(
+#             processor='traversal', op='bytecode',
+#             args={'gremlin': traversal.bytecode,
+#                   'aliases': aliases})
+#         resp = await connection.submit(message)
+#         async for msg in resp:
+#             assert msg == 'person'
+#         traversal = g.V(vid).name
+#         message = request.RequestMessage(
+#             processor='traversal', op='bytecode',
+#             args={'gremlin': traversal.bytecode,
+#                   'aliases': aliases})
+#         resp = await connection.submit(message)
+#         async for msg in resp:
+#             assert msg == 'leifur'
+#
+#
+# @pytest.mark.asyncio
+# async def test_side_effects(remote_graph, connection, aliases):
+#     async with connection:
+#         connection._message_serializer = serializer.GraphSONMessageSerializer()
+#         g = remote_graph.traversal()
+#         # Add some nodes
+#         traversal = g.addV('person').property('name', 'leifur')
+#         resp = await connection.submit(
+#             processor='traversal', op='bytecode', gremlin=traversal.bytecode, aliases=aliases)
+#         async for msg in resp:
+#             pass
+#         traversal = g.addV('person').property('name', 'dave')
+#         resp = await connection.submit(
+#             processor='traversal', op='bytecode', gremlin=traversal.bytecode, aliases=aliases)
+#         async for msg in resp:
+#             pass
+#         traversal = g.addV('person').property('name', 'jonathan')
+#         resp = await connection.submit(
+#             processor='traversal', op='bytecode', gremlin=traversal.bytecode, aliases=aliases)
+#         async for msg in resp:
+#             pass
+#
+#         # # Make a query
+#         traversal = g.V().aggregate('a').aggregate('b')
+#         resp = await connection.submit(
+#             processor='traversal', op='bytecode', gremlin=traversal.bytecode, aliases=aliases)
+#         request_id = resp.request_id
+#         async for msg in resp:
+#             pass
+#         resp = await connection.submit(processor='traversal', op='keys',
+#                                        sideEffect=request_id, aliases=aliases)
+#         keys = []
+#         async for msg in resp:
+#             keys.append(msg)
+#         assert keys == ['a', 'b']
+#
+#         resp = await connection.submit(processor='traversal', op='gather',
+#                                        sideEffect=request_id,
+#                                        sideEffectKey='a', aliases=aliases)
+#         side_effects = []
+#         async for msg in resp:
+#             side_effects.append(msg)
+#         assert side_effects
+#
+#         # Close isn't implmented yet
+#         # resp = await connection.submit(processor='traversal', op='close',
+#         #                                sideEffect=request_id)
+#         # async for msg in resp:
+#         #     print(msg)
+#
+#
+# @pytest.mark.asyncio
+# async def test_session(connection, aliases):
+#     async with connection:
+#         connection._message_serializer = serializer.GraphSONMessageSerializer()
+#         session = str(uuid.uuid4())
+#         resp = await connection.submit(
+#             gremlin="v = g.addV('person').property('name', 'unused_name').next(); v",
+#             processor='session',
+#             op='eval',
+#             session=session,
+#             aliases=aliases)
+#         async for msg in resp:
+#             assert msg['label'] == 'person'
+#         resp = await connection.submit(
+#             gremlin="v.values('name')",
+#             processor='session',
+#             op='eval',
+#             session=session,
+#             aliases=aliases)
+#         async for msg in resp:
+#             assert msg == 'unused_name'
+#         # Close isnt' implemented yet
+#         # resp = await connection.submit(
+#         #     processor='session',
+#         #     op='close',
+#         #     session=session)
+#         # async for msg in resp:
+#         #     print(msg)
diff --git a/tests/test_gremlin_python/__init__.py b/tests/test_gremlin_python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6df110081846e563a662bdf254f6640f35d621b2
--- /dev/null
+++ b/tests/test_gremlin_python/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
\ No newline at end of file
diff --git a/tests/test_gremlin_python/conftest.py b/tests/test_gremlin_python/conftest.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bac4aec88f7bcb82da51f15d7089e5b25b8918b
--- /dev/null
+++ b/tests/test_gremlin_python/conftest.py
@@ -0,0 +1,46 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+import pytest
+
+from aiogremlin.remote.driver_remote_connection import (
+    DriverRemoteConnection)
+from aiogremlin.driver.protocol import GremlinServerWSProtocol
+from aiogremlin.driver.aiohttp.transport import AiohttpTransport
+from aiogremlin.gremlin_python.driver.serializer import GraphSONMessageSerializer
+
+
+@pytest.fixture
+def client(event_loop, cluster):
+    try:
+        client = event_loop.run_until_complete(cluster.connect())
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    else:
+        return client
+
+@pytest.fixture
+def remote_connection(event_loop, gremlin_url):
+    try:
+        remote_conn = event_loop.run_until_complete(
+            DriverRemoteConnection.open(gremlin_url, 'g'))
+    except OSError:
+        pytest.skip('Gremlin Server is not running')
+    else:
+        return remote_conn
diff --git a/tests/test_gremlin_python/driver/__init__.py b/tests/test_gremlin_python/driver/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6df110081846e563a662bdf254f6640f35d621b2
--- /dev/null
+++ b/tests/test_gremlin_python/driver/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
\ No newline at end of file
diff --git a/tests/test_gremlin_python/driver/test_client.py b/tests/test_gremlin_python/driver/test_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..da0f9dc5cc1ae85be6beaf90d162a74f165a230e
--- /dev/null
+++ b/tests/test_gremlin_python/driver/test_client.py
@@ -0,0 +1,83 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+import pytest
+
+from aiogremlin.gremlin_python.driver.request import RequestMessage
+from aiogremlin.gremlin_python.structure.graph import Graph
+
+__author__ = 'David M. Brown (davebshow@gmail.com)'
+
+
+@pytest.mark.asyncio
+async def test_connection(connection):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode})
+    results_set = await connection.write(message)
+    results = await results_set.all()
+    assert len(results) == 6
+    assert isinstance(results, list)
+    await connection.close()
+
+
+@pytest.mark.asyncio
+async def test_client_simple_eval(client):
+    result_set = await client.submit('1 + 1')
+    results = await result_set.all()
+    assert results[0] == 2
+    await client.close()
+
+
+@pytest.mark.asyncio
+async def test_client_simple_eval_bindings(client):
+    result_set = await client.submit('x + x', {'x': 2})
+    results = await result_set.all()
+    assert results[0] == 4
+    await client.close()
+
+@pytest.mark.asyncio
+async def test_client_eval_traversal(client):
+    result_set = await client.submit('g.V()')
+    results = await result_set.all()
+    assert len(results) == 6
+    await client.close()
+
+
+@pytest.mark.asyncio
+async def test_client_bytecode(client):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode})
+    result_set = await client.submit(message)
+    results = await result_set.all()
+    assert len(results) == 6
+    await client.close()
+
+@pytest.mark.asyncio
+async def test_iterate_result_set(client):
+    g = Graph().traversal()
+    t = g.V()
+    message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode})
+    result_set = await client.submit(message)
+    results = []
+    async for result in result_set:
+        results.append(result)
+    assert len(results) == 6
+    await client.close()
diff --git a/tests/test_gremlin_python/driver/test_driver_remote_connection.py b/tests/test_gremlin_python/driver/test_driver_remote_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..911c1044bb90c9810d74a33778603a125eda3436
--- /dev/null
+++ b/tests/test_gremlin_python/driver/test_driver_remote_connection.py
@@ -0,0 +1,189 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+import pytest
+
+from aiogremlin.gremlin_python import statics
+from aiogremlin.gremlin_python.statics import long
+from aiogremlin.remote.driver_remote_connection import (
+    DriverRemoteConnection)
+from aiogremlin.gremlin_python.process.traversal import Traverser
+from aiogremlin.gremlin_python.process.traversal import TraversalStrategy
+from aiogremlin.gremlin_python.process.graph_traversal import __
+from aiogremlin.gremlin_python.structure.graph import Graph
+from aiogremlin.gremlin_python.structure.graph import Vertex
+from aiogremlin.gremlin_python.process.strategies import SubgraphStrategy
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+
+class TestDriverRemoteConnection(object):
+
+    @pytest.mark.asyncio
+    async def test_traversals(self, remote_connection):
+        statics.load_statics(globals())
+        g = Graph().traversal().withRemote(remote_connection)
+        result = await g.V().count().toList()
+        assert long(6) == result[0]
+        # #
+        assert Vertex(1) == await g.V(1).next()
+        assert 1 == await g.V(1).id().next()
+        assert Traverser(Vertex(1)) == await g.V(1).nextTraverser()
+        result = await g.V(1).toList()
+        assert 1 == len(result)
+        result = await g.V(1).toList()
+        assert isinstance(result, list)
+        results = g.V().repeat(out()).times(2).name
+        results = await results.toList()
+        assert 2 == len(results)
+        assert "lop" in results
+        assert "ripple" in results
+        # # #
+        assert 10 == await g.V().repeat(both()).times(5)[0:10].count().next()
+        assert 1 == await g.V().repeat(both()).times(5)[0:1].count().next()
+        assert 0 == await g.V().repeat(both()).times(5)[0:0].count().next()
+        assert 4 == await g.V()[2:].count().next()
+        assert 2 == await g.V()[:2].count().next()
+        # # #
+        results = await g.withSideEffect('a',['josh','peter']).V(1).out('created').in_('created').values('name').where(within('a')).toList()
+        assert 2 == len(results)
+        assert 'josh' in results
+        assert 'peter' in results
+        # # # todo: need a traversal metrics deserializer
+        # g.V().out().profile().next()
+        await remote_connection.close()
+
+    @pytest.mark.asyncio
+    async def test_strategies(self, remote_connection):
+        statics.load_statics(globals())
+        #
+        g = Graph().traversal().withRemote(remote_connection). \
+            withStrategies(TraversalStrategy("SubgraphStrategy",
+                                             {"vertices": __.hasLabel("person"),
+                                              "edges": __.hasLabel("created")}))
+        assert 4 == await g.V().count().next()
+        assert 0 == await g.E().count().next()
+        assert 1 == await g.V().label().dedup().count().next()
+        assert "person" == await g.V().label().dedup().next()
+        #
+        g = Graph().traversal().withRemote(remote_connection). \
+            withStrategies(SubgraphStrategy(vertices=__.hasLabel("person"), edges=__.hasLabel("created")))
+        assert 4 == await g.V().count().next()
+        assert 0 == await g.E().count().next()
+        assert 1 == await g.V().label().dedup().count().next()
+        assert "person" == await g.V().label().dedup().next()
+        #
+        g = g.withoutStrategies(SubgraphStrategy). \
+            withComputer(vertices=__.has("name", "marko"), edges=__.limit(0))
+        assert 1 == await g.V().count().next()
+        assert 0 == await g.E().count().next()
+        assert "person" == await g.V().label().next()
+        assert "marko" == await g.V().name.next()
+        #
+        g = Graph().traversal().withRemote(remote_connection).withComputer()
+        assert 6 == await g.V().count().next()
+        assert 6 == await g.E().count().next()
+        await remote_connection.close()
+
+    @pytest.mark.asyncio
+    async def test_side_effects(self, remote_connection):
+        statics.load_statics(globals())
+        g = Graph().traversal().withRemote(remote_connection)
+        t = await g.V().hasLabel("project").name.iterate()
+        keys = await t.side_effects.keys()
+        assert 0 == len(keys)
+        with pytest.raises(Exception):
+            m = await t.side_effects["m"]
+        t = g.V().out("created").groupCount("m").by("name")
+        results = await t.toSet()
+        assert 2 == len(results)
+        assert Vertex(3) in results
+        assert Vertex(5) in results
+        keys = await t.side_effects.keys()
+        assert 1 == len(keys)
+        assert "m" in keys
+        m = await t.side_effects["m"]
+        assert isinstance(m, dict)
+        assert 2 == len(m)
+        assert 3 == m["lop"]
+        assert 1 == m["ripple"]
+        assert isinstance(m["lop"], long)
+        assert isinstance(m["ripple"], long)
+        # ##
+        t = g.V().out("created").groupCount("m").by("name").name.aggregate("n")
+        results = await t.toSet()
+        assert 2 == len(results)
+        assert "lop" in results
+        assert "ripple" in results
+        keys = await t.side_effects.keys()
+        assert 2 == len(keys)
+        assert "m" in keys
+        assert "n" in keys
+        n = await t.side_effects.get("n")
+        assert isinstance(n, dict)
+        assert 2 == len(n)
+        assert "lop" in n.keys()
+        assert "ripple" in n.keys()
+        assert 3 == n["lop"]
+        assert 1 == n["ripple"]
+        #
+        t = g.withSideEffect('m', 32).V().map(lambda: "x: x.sideEffects('m')")
+        results = await t.toSet()
+        assert 1 == len(results)
+        assert 32 == list(results)[0]
+        assert 32 == await t.side_effects['m']
+        keys = await t.side_effects.keys()
+        assert 1 == len(keys)
+        with pytest.raises(Exception):
+            x = await t.side_effects["x"]
+        await remote_connection.close()
+
+    @pytest.mark.asyncio
+    async def test_side_effect_close(self, remote_connection):
+        g = Graph().traversal().withRemote(remote_connection)
+        t = g.V().aggregate('a').aggregate('b')
+        await t.iterate()
+
+        # The 'a' key should return some side effects
+        results = await t.side_effects.get('a')
+        assert results
+
+        # Close result is None
+        results = await t.side_effects.close()
+        assert not results
+
+        # Shouldn't get any new info from server
+        # 'b' isn't in local cache
+        results = await t.side_effects.get('b')
+        assert not results
+
+        # But 'a' should still be cached locally
+        results = await t.side_effects.get('a')
+        assert results
+
+        # 'a' should have been added to local keys cache, but not 'b'
+        results = await t.side_effects.keys()
+        assert len(results) == 1
+        a, = results
+        assert a == 'a'
+
+        # Try to get 'b' directly from server, should throw error
+        with pytest.raises(Exception):
+            await t.side_effects._get('b')
+        await remote_connection.close()
diff --git a/tests/test_gremlin_python/process/__init__.py b/tests/test_gremlin_python/process/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6df110081846e563a662bdf254f6640f35d621b2
--- /dev/null
+++ b/tests/test_gremlin_python/process/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
\ No newline at end of file
diff --git a/tests/test_gremlin_python/process/test_strategies.py b/tests/test_gremlin_python/process/test_strategies.py
new file mode 100644
index 0000000000000000000000000000000000000000..133f46f9b3ff06dcb9ad845ab81347d4ddfc0aae
--- /dev/null
+++ b/tests/test_gremlin_python/process/test_strategies.py
@@ -0,0 +1,106 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import unittest
+from unittest import TestCase
+
+from aiogremlin.gremlin_python.structure.graph import Graph
+from aiogremlin.gremlin_python.process.strategies import *
+from aiogremlin.gremlin_python.process.graph_traversal import __
+
+
+class TestTraversalStrategies(TestCase):
+    def test_singletons(self):
+        g = Graph().traversal()
+        bytecode = g.withStrategies(ReadOnlyStrategy()).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert "ReadOnlyStrategy" == str(bytecode.source_instructions[0][1])
+        assert hash(ReadOnlyStrategy()) == hash(bytecode.source_instructions[0][1])
+        assert 0 == len(g.traversal_strategies.traversal_strategies)  # these strategies are proxies
+        ##
+        g = g.withStrategies(ReadOnlyStrategy(), IncidentToAdjacentStrategy())
+        bytecode = g.bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        ##
+        bytecode = g.V().bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        assert 1 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+        ##
+        bytecode = g.withoutStrategies(ReadOnlyStrategy()).V().bytecode
+        assert 2 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert 2 == len(bytecode.source_instructions[1])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        assert "withoutStrategies" == bytecode.source_instructions[1][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[1][1]
+        assert 1 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+        ##
+        bytecode = g.withoutStrategies(ReadOnlyStrategy(), LazyBarrierStrategy()).V().bytecode
+        assert 2 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert 3 == len(bytecode.source_instructions[1])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        assert "withoutStrategies" == bytecode.source_instructions[1][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[1][1]
+        assert LazyBarrierStrategy() == bytecode.source_instructions[1][2]
+        assert 1 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+
+    def test_configurable(self):
+        g = Graph().traversal()
+        bytecode = g.withStrategies(MatchAlgorithmStrategy("greedy")).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert MatchAlgorithmStrategy() == bytecode.source_instructions[0][1]
+        assert "MatchAlgorithmStrategy" == str(bytecode.source_instructions[0][1])
+        assert hash(MatchAlgorithmStrategy()) == hash(
+            bytecode.source_instructions[0][1])  # even though different confs, same strategy
+        assert 0 == len(g.traversal_strategies.traversal_strategies)  # these strategies are proxies
+        ###
+        bytecode = g.withStrategies(SubgraphStrategy(vertices=__.has("name","marko"))).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert SubgraphStrategy() == bytecode.source_instructions[0][1]
+        strategy = bytecode.source_instructions[0][1]
+        assert 1 == len(strategy.configuration)
+        assert __.has("name","marko") == strategy.configuration["vertices"]
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_gremlin_python/process/test_traversal.py b/tests/test_gremlin_python/process/test_traversal.py
new file mode 100644
index 0000000000000000000000000000000000000000..325a7c914f098fedd3c8c5f01d9a5a515a241051
--- /dev/null
+++ b/tests/test_gremlin_python/process/test_traversal.py
@@ -0,0 +1,91 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import unittest
+from unittest import TestCase
+
+from aiogremlin.gremlin_python.structure.graph import Graph
+from aiogremlin.gremlin_python.process.traversal import P
+from aiogremlin.gremlin_python.process.traversal import Binding
+from aiogremlin.gremlin_python.process.graph_traversal import __
+
+
+class TestTraversal(TestCase):
+    def test_bytecode(self):
+        g = Graph().traversal()
+        bytecode = g.V().out("created").bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 0 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+        assert "out" == bytecode.step_instructions[1][0]
+        assert "created" == bytecode.step_instructions[1][1]
+        assert 1 == len(bytecode.step_instructions[0])
+        assert 2 == len(bytecode.step_instructions[1])
+        ##
+        bytecode = g.withSack(1).E().groupCount().by("weight").bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 1 == len(bytecode.source_instructions)
+        assert "withSack" == bytecode.source_instructions[0][0]
+        assert 1 == bytecode.source_instructions[0][1]
+        assert 3 == len(bytecode.step_instructions)
+        assert "E" == bytecode.step_instructions[0][0]
+        assert "groupCount" == bytecode.step_instructions[1][0]
+        assert "by" == bytecode.step_instructions[2][0]
+        assert "weight" == bytecode.step_instructions[2][1]
+        assert 1 == len(bytecode.step_instructions[0])
+        assert 1 == len(bytecode.step_instructions[1])
+        assert 2 == len(bytecode.step_instructions[2])
+        ##
+        bytecode = g.V(('a',[1,2,3])).out(('b','created')).where(__.in_(('c','created'),('d','knows')).count().is_(('e',P.gt(2)))).bytecode
+        assert 5 == len(bytecode.bindings.keys())
+        assert [1,2,3] == bytecode.bindings['a']
+        assert 'created' == bytecode.bindings['b']
+        assert 'created' == bytecode.bindings['c']
+        assert 'knows' == bytecode.bindings['d']
+        assert P.gt(2) == bytecode.bindings['e']
+        assert Binding('b','created') == bytecode.step_instructions[1][1]
+        assert 'binding[b=created]' == str(bytecode.step_instructions[1][1])
+        assert isinstance(hash(bytecode.step_instructions[1][1]),int)
+
+    def test_P(self):
+        # verify that the order of operations is respected
+        assert "and(eq(a),lt(b))" == str(P.eq("a").and_(P.lt("b")))
+        assert "and(or(lt(b),gt(c)),neq(d))" == str(P.lt("b").or_(P.gt("c")).and_(P.neq("d")))
+        assert "and(or(lt(b),gt(c)),or(neq(d),gte(e)))" == str(
+            P.lt("b").or_(P.gt("c")).and_(P.neq("d").or_(P.gte("e"))))
+
+    def test_anonymous_traversal(self):
+        bytecode = __.__(1).bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 0 == len(bytecode.source_instructions)
+        assert 1 == len(bytecode.step_instructions)
+        assert "inject" == bytecode.step_instructions[0][0]
+        assert 1 == bytecode.step_instructions[0][1]
+        ##
+        bytecode = __.start().bytecode
+        assert 0 == len(bytecode.bindings.keys())
+        assert 0 == len(bytecode.source_instructions)
+        assert 0 == len(bytecode.step_instructions)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_gremlin_python/structure/__init__.py b/tests/test_gremlin_python/structure/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6df110081846e563a662bdf254f6640f35d621b2
--- /dev/null
+++ b/tests/test_gremlin_python/structure/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
\ No newline at end of file
diff --git a/tests/test_gremlin_python/structure/io/__init__.py b/tests/test_gremlin_python/structure/io/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6df110081846e563a662bdf254f6640f35d621b2
--- /dev/null
+++ b/tests/test_gremlin_python/structure/io/__init__.py
@@ -0,0 +1,20 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
\ No newline at end of file
diff --git a/tests/test_gremlin_python/structure/io/test_graphson.py b/tests/test_gremlin_python/structure/io/test_graphson.py
new file mode 100644
index 0000000000000000000000000000000000000000..6c88a2d8d0e5940b3652ee5e5bcf25dc27630dfb
--- /dev/null
+++ b/tests/test_gremlin_python/structure/io/test_graphson.py
@@ -0,0 +1,206 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import json
+from mock import Mock
+import unittest
+from unittest import TestCase
+
+from aiogremlin.gremlin_python.statics import *
+from aiogremlin.gremlin_python.structure.graph import Vertex
+from aiogremlin.gremlin_python.structure.graph import Path
+from aiogremlin.gremlin_python.structure.io.graphson import GraphSONWriter, GraphSONReader, GraphSONUtil
+import aiogremlin.gremlin_python.structure.io.graphson
+from aiogremlin.gremlin_python.process.traversal import P
+from aiogremlin.gremlin_python.process.strategies import SubgraphStrategy
+from aiogremlin.gremlin_python.process.graph_traversal import __
+
+
+class TestGraphSONReader(TestCase):
+    graphson_reader = GraphSONReader()
+
+    def test_number_input(self):
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Int32",
+            "@value": 31
+        }))
+        assert isinstance(x, int)
+        assert 31 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Int64",
+            "@value": 31
+        }))
+        assert isinstance(x, long)
+        assert long(31) == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Float",
+            "@value": 31.3
+        }))
+        assert isinstance(x, float)
+        assert 31.3 == x
+        ##
+        x = self.graphson_reader.readObject(json.dumps({
+            "@type": "g:Double",
+            "@value": 31.2
+        }))
+        assert isinstance(x, float)
+        assert 31.2 == x
+
+    def test_graph(self):
+        vertex = self.graphson_reader.readObject(
+            """{"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""")
+        assert isinstance(vertex, Vertex)
+        assert "person" == vertex.label
+        assert 1 == vertex.id
+        assert isinstance(vertex.id, int)
+        assert vertex == Vertex(1)
+
+    def test_path(self):
+        path = self.graphson_reader.readObject(
+            """{"@type":"g:Path","@value":{"labels":[["a"],["b","c"],[]],"objects":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":3},"label":"software","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":4},"value":"lop","label":"name"}}],"lang":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":5},"value":"java","label":"lang"}}]}}},"lop"]}}"""
+        )
+        assert isinstance(path, Path)
+        assert "[v[1], v[3], 'lop']" == str(path)
+        assert Vertex(1) == path[0]
+        assert Vertex(1) == path["a"]
+        assert "lop" == path[2]
+        assert 3 == len(path)
+
+    def test_custom_mapping(self):
+
+        # extended mapping
+        class X(object):
+            pass
+
+        type_string = "test:Xtype"
+        override_string = "g:Int64"
+        serdes = Mock()
+
+        reader = GraphSONReader(deserializer_map={type_string: serdes})
+        assert type_string in reader.deserializers
+
+        # base dicts are not modified
+        assert type_string not in aiogremlin.gremlin_python.structure.io.graphson._deserializers
+
+        x = X()
+        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: x})
+        serdes.objectify.assert_called_once_with(x, reader)
+        assert o is serdes.objectify()
+
+        # overridden mapping
+        type_string = "g:Int64"
+        serdes = Mock()
+        reader = GraphSONReader(deserializer_map={type_string: serdes, override_string: serdes})
+        assert aiogremlin.gremlin_python.structure.io.graphson._deserializers[type_string] is not reader.deserializers[type_string]
+
+        value = 3
+        o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: value})
+        serdes.objectify.assert_called_once_with(value, reader)
+        assert o is serdes.objectify()
+
+
+class TestGraphSONWriter(TestCase):
+
+    graphson_writer = GraphSONWriter()
+
+    def test_number_output(self):
+        assert {"@type":"g:Int64","@value":2} == json.loads(self.graphson_writer.writeObject(long(2)))
+        assert {"@type":"g:Int32","@value":1} == json.loads(self.graphson_writer.writeObject(1))
+        assert {"@type":"g:Double","@value":3.2} == json.loads(self.graphson_writer.writeObject(3.2))
+        assert """true""" == self.graphson_writer.writeObject(True)
+
+    def test_numbers(self):
+        assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.writeObject(long(2)))
+        assert {"@type": "g:Int32", "@value": 1} == json.loads(self.graphson_writer.writeObject(1))
+        assert {"@type": "g:Double", "@value": 3.2} == json.loads(self.graphson_writer.writeObject(3.2))
+        assert """true""" == self.graphson_writer.writeObject(True)
+
+    def test_P(self):
+        result = {'@type': 'g:P',
+                  '@value': {
+                     'predicate': 'and',
+                     'value': [{
+                        '@type': 'g:P',
+                        '@value': {
+                            'predicate': 'or',
+                            'value': [{
+                                '@type': 'g:P',
+                                '@value': {'predicate': 'lt', 'value': 'b'}
+                            },
+                            {'@type': 'g:P', '@value': {'predicate': 'gt', 'value': 'c'}}
+                            ]
+                        }
+                    },
+                    {'@type': 'g:P', '@value': {'predicate': 'neq', 'value': 'd'}}]}}
+
+        assert  result == json.loads(
+            self.graphson_writer.writeObject(P.lt("b").or_(P.gt("c")).and_(P.neq("d"))))
+
+    def test_strategies(self):
+        # we have a proxy model for now given that we don't want to have to have g:XXX all registered on the Gremlin traversal machine (yet)
+        assert {"@type": "g:SubgraphStrategy", "@value": {}} == json.loads(self.graphson_writer.writeObject(SubgraphStrategy))
+        assert {"@type": "g:SubgraphStrategy", "@value": {
+            "vertices": {"@type": "g:Bytecode", "@value": {"step": [["has", "name", "marko"]]}}}} == json.loads(
+            self.graphson_writer.writeObject(SubgraphStrategy(vertices=__.has("name", "marko"))))
+
+    def test_custom_mapping(self):
+
+        # extended mapping
+        class X(object):
+            pass
+
+        serdes = Mock()
+        writer = GraphSONWriter(serializer_map={X: serdes})
+        assert X in writer.serializers
+
+        # base dicts are not modified
+        assert X not in aiogremlin.gremlin_python.structure.io.graphson._serializers
+
+        obj = X()
+        d = writer.toDict(obj)
+        serdes.dictify.assert_called_once_with(obj, writer)
+        assert d is serdes.dictify()
+
+        # overridden mapping
+        serdes = Mock()
+        writer = GraphSONWriter(serializer_map={int: serdes})
+        assert aiogremlin.gremlin_python.structure.io.graphson._serializers[int] is not writer.serializers[int]
+
+        value = 3
+        d = writer.toDict(value)
+        serdes.dictify.assert_called_once_with(value, writer)
+        assert d is serdes.dictify()
+
+    def test_write_long(self):
+
+        mapping = self.graphson_writer.toDict(1)
+        assert mapping['@type'] == 'g:Int32'
+        assert mapping['@value'] == 1
+
+        mapping = self.graphson_writer.toDict(long(1))
+        assert mapping['@type'] == 'g:Int64'
+        assert mapping['@value'] == 1
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_gremlin_python/structure/test_graph.py b/tests/test_gremlin_python/structure/test_graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..98b48ba12b69c7b86c5ca4e62a27547675afdb08
--- /dev/null
+++ b/tests/test_gremlin_python/structure/test_graph.py
@@ -0,0 +1,116 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import unittest
+from unittest import TestCase
+
+from aiogremlin.gremlin_python.statics import long
+from aiogremlin.gremlin_python.structure.graph import Edge
+from aiogremlin.gremlin_python.structure.graph import Property
+from aiogremlin.gremlin_python.structure.graph import Vertex
+from aiogremlin.gremlin_python.structure.graph import VertexProperty
+from aiogremlin.gremlin_python.structure.graph import Path
+
+
+class TestGraph(TestCase):
+    def test_graph_objects(self):
+        vertex = Vertex(1)
+        assert "v[1]" == str(vertex)
+        assert "vertex" == vertex.label
+        assert "person" == Vertex(1, "person").label
+        assert vertex == Vertex(1)
+        #
+        edge = Edge(2, Vertex(1), "said", Vertex("hello", "phrase"))
+        assert "e[2][1-said->hello]" == str(edge)
+        assert Vertex(1) == edge.outV
+        assert Vertex("hello") == edge.inV
+        assert "said" == edge.label
+        assert "phrase" == edge.inV.label
+        assert edge.inV != edge.outV
+        #
+        vertex_property = VertexProperty(long(24), "name", "marko")
+        assert "vp[name->marko]" == str(vertex_property)
+        assert "name" == vertex_property.label
+        assert "name" == vertex_property.key
+        assert "marko" == vertex_property.value
+        assert long(24) == vertex_property.id
+        assert isinstance(vertex_property.id, long)
+        assert vertex_property == VertexProperty(long(24), "name", "marko")
+        #
+        property = Property("age", 29)
+        assert "p[age->29]" == str(property)
+        assert "age" == property.key
+        assert 29 == property.value
+        assert isinstance(property.value, int)
+        assert property == Property("age", 29)
+        #
+        for i in [vertex, edge, vertex_property, property]:
+            for j in [vertex, edge, vertex_property, property]:
+                if type(i) != type(j):
+                    assert i != j
+                else:
+                    assert i == j
+                    assert i.__hash__() == hash(i)
+
+    def test_path(self):
+        path = Path([set(["a", "b"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
+        assert "[1, v[1], 'hello']" == str(path)
+        assert 1 == path["a"]
+        assert Vertex(1) == path["c"]
+        assert [1, Vertex(1)] == path["b"]
+        assert path[0] == 1
+        assert path[1] == Vertex(1)
+        assert path[2] == "hello"
+        assert 3 == len(path)
+        assert "hello" in path
+        assert "goodbye" not in path
+        assert Vertex(1) in path
+        assert Vertex(123) not in path
+        #
+        try:
+            temp = path[3]
+            raise Exception("Accessing beyond the list index should throw an index error")
+        except IndexError:
+            pass
+        #
+        try:
+            temp = path["zz"]
+            raise Exception("Accessing nothing should throw a key error")
+        except KeyError:
+            pass
+        #
+        try:
+            temp = path[1:2]
+            raise Exception("Accessing using slices should throw a type error")
+        except TypeError:
+            pass
+        #
+        assert path == path
+        assert hash(path) == hash(path)
+        path2 = Path([set(["a", "b"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
+        assert path == path2
+        assert hash(path) == hash(path2)
+        assert path != Path([set(["a"]), set(["c", "b"]), set([])], [1, Vertex(1), "hello"])
+        assert path != Path([set(["a", "b"]), set(["c", "b"]), set([])], [3, Vertex(1), "hello"])
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_gremlin_python/test_statics.py b/tests/test_gremlin_python/test_statics.py
new file mode 100644
index 0000000000000000000000000000000000000000..ea2e993584ba3217f10136cf5db377716a2e88a4
--- /dev/null
+++ b/tests/test_gremlin_python/test_statics.py
@@ -0,0 +1,46 @@
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+'''
+'''THIS FILE HAS BEEN MODIFIED BY DAVID M. BROWN TO SUPPORT PEP 492'''
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import unittest
+from unittest import TestCase
+
+from aiogremlin.gremlin_python import statics
+from aiogremlin.gremlin_python.process.traversal import Cardinality
+from aiogremlin.gremlin_python.process.traversal import P
+from aiogremlin.gremlin_python.process.traversal import Pop
+
+
+class TestStatics(TestCase):
+    def test_enums(self):
+        statics.load_statics(globals())
+        assert isinstance(list_, Cardinality)
+        assert list_ is Cardinality.list_
+        #
+        assert isinstance(eq(2), P)
+        assert eq(2) == P.eq(2)
+        #
+        assert isinstance(first, Pop)
+        assert first == Pop.first
+        statics.unload_statics(globals())
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_pool.py b/tests/test_pool.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf1eef666c0b84008feab16eb94b9c0a43d26735
--- /dev/null
+++ b/tests/test_pool.py
@@ -0,0 +1,105 @@
+# Copyright 2016 David M. Brown
+#
+# This file is part of Goblin.
+#
+# Goblin is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Goblin is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Goblin.  If not, see <http://www.gnu.org/licenses/>.
+
+import asyncio
+import pytest
+
+
+@pytest.mark.asyncio
+async def test_pool_init(connection_pool):
+    await connection_pool.init_pool()
+    assert len(connection_pool._available) == 1
+    await connection_pool.close()
+
+
+@pytest.mark.asyncio
+async def test_acquire_release(connection_pool):
+    conn = await connection_pool.acquire()
+    assert not len(connection_pool._available)
+    assert len(connection_pool._acquired) == 1
+    assert conn.times_acquired == 1
+    connection_pool.release(conn)
+    assert len(connection_pool._available) == 1
+    assert not len(connection_pool._acquired)
+    assert not conn.times_acquired
+    await connection_pool.close()
+
+
+@pytest.mark.asyncio
+async def test_acquire_multiple(connection_pool):
+    conn1 = await connection_pool.acquire()
+    conn2 = await connection_pool.acquire()
+    assert not conn1 is conn2
+    assert len(connection_pool._acquired) == 2
+    await connection_pool.close()
+
+
+@pytest.mark.asyncio
+async def test_share(connection_pool):
+    connection_pool._max_conns = 1
+    conn1 = await connection_pool.acquire()
+    conn2 = await connection_pool.acquire()
+    assert conn1 is conn2
+    assert conn1.times_acquired == 2
+    await connection_pool.close()
+
+
+@pytest.mark.asyncio
+async def test_acquire_multiple_and_share(connection_pool):
+    connection_pool._max_conns = 2
+    connection_pool._max_times_acquired = 2
+    conn1 = await connection_pool.acquire()
+    conn2 = await connection_pool.acquire()
+    assert not conn1 is conn2
+    conn3 = await connection_pool.acquire()
+    conn4 = await connection_pool.acquire()
+    assert not conn3 is conn4
+    assert conn3 is conn1
+    assert conn4 is conn2
+    await connection_pool.close()
+
+
+@pytest.mark.asyncio
+async def test_max_acquired(connection_pool):
+    connection_pool._max_conns = 2
+    connection_pool._max_times_acquired = 2
+    conn1 = await connection_pool.acquire()
+    conn2 = await connection_pool.acquire()
+    conn3 = await connection_pool.acquire()
+    conn4 = await connection_pool.acquire()
+    with pytest.raises(asyncio.TimeoutError):
+        await asyncio.wait_for(connection_pool.acquire(), timeout=0.1)
+    await connection_pool.close()
+
+
+@pytest.mark.asyncio
+async def test_release_notify(connection_pool):
+    connection_pool._max_conns = 2
+    connection_pool._max_times_acquired = 2
+    conn1 = await connection_pool.acquire()
+    conn2 = await connection_pool.acquire()
+    conn3 = await connection_pool.acquire()
+    conn4 = await connection_pool.acquire()
+
+    async def release(conn):
+        conn.release()
+
+    results = await asyncio.gather(
+        *[connection_pool.acquire(), release(conn4)])
+    conn4 = results[0]
+    assert conn4 is conn2
+    await connection_pool.close()
diff --git a/tests/test_provider_conf.py b/tests/test_provider_conf.py
new file mode 100644
index 0000000000000000000000000000000000000000..5e92bbf1a5c7f3047371c47c1f97dab7685a9adf
--- /dev/null
+++ b/tests/test_provider_conf.py
@@ -0,0 +1,144 @@
+# import asyncio
+# import uuid
+# from unittest import mock
+#
+# import json
+# import pytest
+#
+# import aiohttp
+# from aiohttp import client_ws
+#
+# import goblin
+# from goblin import driver
+# from aiogremlin import serializer
+# from goblin import provider
+#
+# request_id = uuid.UUID(int=215449331521667564889692237976543325869, version=4)
+#
+#
+# # based on this handy tip on SO: http://stackoverflow.com/a/29905620/6691423
+# def get_mock_coro(return_value):
+#     async def mock_coro(*args, **kwargs):
+#         return return_value
+#
+#     return mock.Mock(wraps=mock_coro)
+#
+#
+# async def mock_receive():
+#     message = mock.Mock()
+#     message.tp = aiohttp.MsgType.close
+#     return message
+#
+#
+# async def mock_ws_connect(*args, **kwargs):
+#     mock_client = mock.Mock(spec=client_ws.ClientWebSocketResponse)
+#     mock_client.closed = False
+#     mock_client.receive = mock.Mock(wraps=mock_receive)
+#     mock_client.close = get_mock_coro(None)
+#     return mock_client
+#
+#
+# class TestProvider(provider.Provider):
+#     DEFAULT_OP_ARGS = {
+#         'standard': {
+#             'eval': {
+#                 'fictional_argument': 'fictional_value'
+#             },
+#         },
+#         'session': {
+#             'eval': {
+#                 'manageTransaction': True
+#             },
+#
+#         }
+#     }
+#
+#     @staticmethod
+#     def get_hashable_id(val):
+#         return val
+#
+#
+# def deserialize_json_request(request):
+#     header_len = request[0] + 1
+#     payload = request[header_len:]
+#     return json.loads(payload.decode())
+#
+#
+# @pytest.fixture(params=(
+#         serializer.GraphSONMessageSerializer,
+#         serializer.GraphSONMessageSerializer
+# ))
+# def message_serializer(request):
+#     return request.param
+#
+#
+# @pytest.mark.parametrize('processor_name,key,value', (
+#         ('standard', 'fictional_argument', 'fictional_value'),
+#         ('session', 'manageTransaction', True)
+# ))
+# def test_get_processor_provider_default_args(processor_name, key, value):
+#     processor = serializer.GraphSONMessageSerializer.get_processor(TestProvider, processor_name)
+#     assert processor._default_args == TestProvider.DEFAULT_OP_ARGS[processor_name]
+#     eval_args = processor.get_op_args('eval', {'gremlin': 'g.V()'})
+#     assert eval_args['gremlin'] == 'g.V()'
+#     assert eval_args[key] == value
+#
+#
+# @pytest.mark.parametrize('processor,key,value', (
+#         ('', 'fictional_argument', 'fictional_value'),
+#         ('session', 'manageTransaction', True)
+# ))
+# def test_serializer_default_op_args(message_serializer, processor, key, value):
+#     g = driver.AsyncGraph().traversal()
+#     traversal = g.V().hasLabel('stuff').has('foo', 'bar')
+#     serialized_message = message_serializer.serialize_message(
+#         TestProvider, str(uuid.uuid4()), processor=processor, op='eval', gremlin=traversal.bytecode)
+#     message = deserialize_json_request(serialized_message)
+#     assert message['args'][key] == value
+#
+#
+# @pytest.mark.parametrize('processor,key,value', (
+#         ('', 'fictional_argument', 'fictional_value'),
+#         ('session', 'manageTransaction', True)
+# ))
+# @pytest.mark.asyncio
+# async def test_conn_default_op_args(event_loop, monkeypatch, processor, key, value):
+#     mock_client_session = mock.Mock(spec=aiohttp.ClientSession)
+#     mock_client_session_instance = mock.Mock(spec=aiohttp.ClientSession)
+#     mock_client_session.return_value = mock_client_session_instance
+#     mock_client_session_instance.ws_connect = mock.Mock(wraps=mock_ws_connect)
+#     mock_client_session_instance.close = get_mock_coro(None)  # otherwise awaiting ws.close is an error
+#
+#     monkeypatch.setattr(aiohttp, 'ClientSession', mock_client_session)
+#     monkeypatch.setattr(uuid, 'uuid4', mock.Mock(return_value=request_id))
+#
+#     conn = await driver.Connection.open(
+#         'some_url',
+#         event_loop,
+#         message_serializer=serializer.GraphSONMessageSerializer,
+#         provider=TestProvider
+#     )
+#
+#     resp = await conn.submit(
+#         gremlin='g.V().hasLabel("foo").count()', processor=processor, op='eval')
+#
+#     submitted_bytes = conn._ws.send_bytes.call_args[0][0]
+#     submitted_json = submitted_bytes[17:].decode()
+#     submitted_dict = json.loads(submitted_json)
+#
+#     assert submitted_dict['args'][key] == value
+#
+#     await conn.close()
+#     resp.close()
+#
+#
+# @pytest.mark.asyncio
+# async def test_cluster_conn_provider(event_loop, gremlin_host, gremlin_port):
+#     cluster = await driver.Cluster.open(
+#         event_loop, provider=TestProvider, hosts=[gremlin_host], port=gremlin_port)
+#     assert cluster.config['provider'] == TestProvider
+#
+#     pooled_conn = await cluster.get_connection()
+#     assert pooled_conn._conn._provider == TestProvider
+#
+#     await cluster.close()
diff --git a/tests/test_sasl.py b/tests/test_sasl.py
deleted file mode 100644
index 59e403e615452622b427aaaf9029d928ccaf7b34..0000000000000000000000000000000000000000
--- a/tests/test_sasl.py
+++ /dev/null
@@ -1,264 +0,0 @@
-"""
-"""
-
-import asyncio
-import unittest
-import uuid
-import aiohttp
-from aiogremlin import (submit, GremlinConnector, GremlinClient,
-                        GremlinClientSession, GremlinServerError,
-                        GremlinClientWebSocketResponse)
-
-
-class SubmitTest(unittest.TestCase):
-
-    def setUp(self):
-        self.loop = asyncio.new_event_loop()
-        asyncio.set_event_loop(None)
-
-    def tearDown(self):
-        self.loop.close()
-
-    def test_submit(self):
-
-        @asyncio.coroutine
-        def go():
-            resp = yield from submit("x + x", url='https://localhost:8182/',
-                                     bindings={"x": 4}, loop=self.loop,
-                                     username="stephen", password="password")
-            results = yield from resp.get()
-            return results
-        results = self.loop.run_until_complete(go())
-        self.assertEqual(results[0].data[0], 8)
-
-    def test_rebinding(self):
-
-        @asyncio.coroutine
-        def go1():
-            result = yield from submit("graph2.addVertex()",
-                                       url='https://localhost:8182/',
-                                       loop=self.loop, username="stephen",
-                                       password="password")
-            resp = yield from result.get()
-
-        try:
-            self.loop.run_until_complete(go1())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-        @asyncio.coroutine
-        def go2():
-            result = yield from submit(
-                "graph2.addVertex()", url='https://localhost:8182/',
-                rebindings={"graph2": "graph"}, loop=self.loop,
-                username="stephen", password="password")
-            resp = yield from result.get()
-            self.assertEqual(len(resp), 1)
-
-        try:
-            self.loop.run_until_complete(go2())
-        except GremlinServerError:
-            print("RELEASE DOES NOT SUPPORT REBINDINGS")
-
-
-class GremlinClientTest(unittest.TestCase):
-
-    def setUp(self):
-        self.loop = asyncio.new_event_loop()
-        asyncio.set_event_loop(None)
-        connector = aiohttp.TCPConnector(force_close=False, loop=self.loop,
-                                         verify_ssl=False)
-
-        client_session = aiohttp.ClientSession(
-            connector=connector, loop=self.loop,
-            ws_response_class=GremlinClientWebSocketResponse)
-
-        self.gc = GremlinClient(url="https://localhost:8182/", loop=self.loop,
-                                username="stephen", password="password",
-                                client_session=client_session)
-
-    def tearDown(self):
-        self.loop.run_until_complete(self.gc.close())
-        self.loop.close()
-
-    def test_connection(self):
-
-        @asyncio.coroutine
-        def go():
-            ws = yield from self.gc._connector.ws_connect(self.gc.url)
-            self.assertFalse(ws.closed)
-            yield from ws.close()
-
-        self.loop.run_until_complete(go())
-
-    def test_execute(self):
-
-        @asyncio.coroutine
-        def go():
-            resp = yield from self.gc.execute("x + x", bindings={"x": 4})
-            return resp
-
-        results = self.loop.run_until_complete(go())
-        self.assertEqual(results[0].data[0], 8)
-
-    def test_sub_waitfor(self):
-        sub1 = self.gc.execute("x + x", bindings={"x": 1})
-        sub2 = self.gc.execute("x + x", bindings={"x": 2})
-        sub3 = self.gc.execute("x + x", bindings={"x": 4})
-        coro = asyncio.gather(*[asyncio.async(sub1, loop=self.loop),
-                              asyncio.async(sub2, loop=self.loop),
-                              asyncio.async(sub3, loop=self.loop)],
-                              loop=self.loop)
-        # Here I am looking for resource warnings.
-        results = self.loop.run_until_complete(coro)
-        self.assertIsNotNone(results)
-
-    def test_resp_stream(self):
-        @asyncio.coroutine
-        def stream_coro():
-            results = []
-            resp = yield from self.gc.submit("x + x", bindings={"x": 4})
-            while True:
-                f = yield from resp.stream.read()
-                if f is None:
-                    break
-                results.append(f)
-            self.assertEqual(results[0].data[0], 8)
-        self.loop.run_until_complete(stream_coro())
-
-    def test_execute_error(self):
-        execute = self.gc.execute("x + x g.asdfas", bindings={"x": 4})
-        try:
-            self.loop.run_until_complete(execute)
-            error = False
-        except:
-            error = True
-        self.assertTrue(error)
-
-    def test_rebinding(self):
-        execute = self.gc.execute("graph2.addVertex()")
-        try:
-            self.loop.run_until_complete(execute)
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-        @asyncio.coroutine
-        def go():
-            result = yield from self.gc.execute(
-                "graph2.addVertex()", rebindings={"graph2": "graph"})
-            self.assertEqual(len(result), 1)
-
-        try:
-            self.loop.run_until_complete(go())
-        except GremlinServerError:
-            print("RELEASE DOES NOT SUPPORT REBINDINGS")
-
-
-class GremlinClientSessionTest(unittest.TestCase):
-
-    def setUp(self):
-        self.loop = asyncio.new_event_loop()
-        asyncio.set_event_loop(None)
-        connector = aiohttp.TCPConnector(force_close=False, loop=self.loop,
-                                         verify_ssl=False)
-
-        client_session = aiohttp.ClientSession(
-            connector=connector, loop=self.loop,
-            ws_response_class=GremlinClientWebSocketResponse)
-
-        self.gc = GremlinClientSession(url="https://localhost:8182/",
-                                       loop=self.loop,
-                                       username="stephen", password="password",
-                                       client_session=client_session)
-
-        self.script1 = """v=graph.addVertex('name', 'Dave')"""
-
-        self.script2 = "v.property('name')"
-
-    def tearDown(self):
-        self.loop.run_until_complete(self.gc.close())
-        self.loop.close()
-
-    def test_session(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            results = yield from self.gc.execute(self.script2)
-            return results
-
-        results = self.loop.run_until_complete(go())
-        self.assertEqual(results[0].data[0]['value'], 'Dave')
-
-    def test_session_reset(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            self.gc.reset_session()
-            results = yield from self.gc.execute(self.script2)
-            return results
-        try:
-            results = self.loop.run_until_complete(go())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-    def test_session_manual_reset(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            new_sess = str(uuid.uuid4())
-            sess = self.gc.reset_session(session=new_sess)
-            self.assertEqual(sess, new_sess)
-            self.assertEqual(self.gc.session, new_sess)
-            results = yield from self.gc.execute(self.script2)
-            return results
-        try:
-            results = self.loop.run_until_complete(go())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-    def test_session_set(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            new_sess = str(uuid.uuid4())
-            self.gc.session = new_sess
-            self.assertEqual(self.gc.session, new_sess)
-            results = yield from self.gc.execute(self.script2)
-            return results
-        try:
-            results = self.loop.run_until_complete(go())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-    def test_resp_session(self):
-
-        @asyncio.coroutine
-        def go():
-            session = str(uuid.uuid4())
-            self.gc.session = session
-            resp = yield from self.gc.submit("x + x", bindings={"x": 4})
-            while True:
-                f = yield from resp.stream.read()
-                if f is None:
-                    break
-            self.assertEqual(resp.session, session)
-
-        self.loop.run_until_complete(go())
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/tests/tests.py b/tests/tests.py
deleted file mode 100644
index b823e7dbd0e13d31187c0579461909a70b677bd7..0000000000000000000000000000000000000000
--- a/tests/tests.py
+++ /dev/null
@@ -1,247 +0,0 @@
-"""
-"""
-
-import asyncio
-import unittest
-import uuid
-import aiohttp
-from aiogremlin import (submit, GremlinConnector, GremlinClient,
-                        GremlinClientSession, GremlinServerError,
-                        GremlinClientWebSocketResponse)
-
-
-class SubmitTest(unittest.TestCase):
-
-    def setUp(self):
-        self.loop = asyncio.new_event_loop()
-        asyncio.set_event_loop(None)
-
-    def tearDown(self):
-        self.loop.close()
-
-    def test_submit(self):
-
-        @asyncio.coroutine
-        def go():
-            resp = yield from submit("x + x", url='http://localhost:8182/',
-                                     bindings={"x": 4}, loop=self.loop,
-                                     username="stephen", password="password")
-            results = yield from resp.get()
-            return results
-        results = self.loop.run_until_complete(go())
-        self.assertEqual(results[0].data[0], 8)
-
-    def test_rebinding(self):
-
-        @asyncio.coroutine
-        def go1():
-            result = yield from submit("graph2.addVertex()",
-                                       url='http://localhost:8182/',
-                                       loop=self.loop, username="stephen",
-                                       password="password")
-            resp = yield from result.get()
-
-        try:
-            self.loop.run_until_complete(go1())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-        @asyncio.coroutine
-        def go2():
-            result = yield from submit(
-                "graph2.addVertex()", url='http://localhost:8182/',
-                rebindings={"graph2": "graph"}, loop=self.loop,
-                username="stephen", password="password")
-            resp = yield from result.get()
-            self.assertEqual(len(resp), 1)
-
-        try:
-            self.loop.run_until_complete(go2())
-        except GremlinServerError:
-            print("RELEASE DOES NOT SUPPORT REBINDINGS")
-
-
-class GremlinClientTest(unittest.TestCase):
-
-    def setUp(self):
-        self.loop = asyncio.new_event_loop()
-        asyncio.set_event_loop(None)
-
-        self.gc = GremlinClient(url="http://localhost:8182/", loop=self.loop)
-
-    def tearDown(self):
-        self.loop.run_until_complete(self.gc.close())
-        self.loop.close()
-
-    def test_connection(self):
-
-        @asyncio.coroutine
-        def go():
-            ws = yield from self.gc._connector.ws_connect(self.gc.url)
-            self.assertFalse(ws.closed)
-            yield from ws.close()
-
-        self.loop.run_until_complete(go())
-
-    def test_execute(self):
-
-        @asyncio.coroutine
-        def go():
-            resp = yield from self.gc.execute("x + x", bindings={"x": 4})
-            return resp
-
-        results = self.loop.run_until_complete(go())
-        self.assertEqual(results[0].data[0], 8)
-
-    def test_sub_waitfor(self):
-        sub1 = self.gc.execute("x + x", bindings={"x": 1})
-        sub2 = self.gc.execute("x + x", bindings={"x": 2})
-        sub3 = self.gc.execute("x + x", bindings={"x": 4})
-        coro = asyncio.gather(*[asyncio.async(sub1, loop=self.loop),
-                              asyncio.async(sub2, loop=self.loop),
-                              asyncio.async(sub3, loop=self.loop)],
-                              loop=self.loop)
-        # Here I am looking for resource warnings.
-        results = self.loop.run_until_complete(coro)
-        self.assertIsNotNone(results)
-
-    def test_resp_stream(self):
-        @asyncio.coroutine
-        def stream_coro():
-            results = []
-            resp = yield from self.gc.submit("x + x", bindings={"x": 4})
-            while True:
-                f = yield from resp.stream.read()
-                if f is None:
-                    break
-                results.append(f)
-            self.assertEqual(results[0].data[0], 8)
-        self.loop.run_until_complete(stream_coro())
-
-    def test_execute_error(self):
-        execute = self.gc.execute("x + x g.asdfas", bindings={"x": 4})
-        try:
-            self.loop.run_until_complete(execute)
-            error = False
-        except:
-            error = True
-        self.assertTrue(error)
-
-    def test_rebinding(self):
-        execute = self.gc.execute("graph2.addVertex()")
-        try:
-            self.loop.run_until_complete(execute)
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-        @asyncio.coroutine
-        def go():
-            result = yield from self.gc.execute(
-                "graph2.addVertex()", rebindings={"graph2": "graph"})
-            self.assertEqual(len(result), 1)
-
-        try:
-            self.loop.run_until_complete(go())
-        except GremlinServerError:
-            print("RELEASE DOES NOT SUPPORT REBINDINGS")
-
-
-class GremlinClientSessionTest(unittest.TestCase):
-
-    def setUp(self):
-        self.loop = asyncio.new_event_loop()
-        asyncio.set_event_loop(None)
-        self.gc = GremlinClientSession(url="http://localhost:8182/",
-                                       loop=self.loop)
-
-        self.script1 = """v=graph.addVertex('name', 'Dave')"""
-
-        self.script2 = "v.property('name')"
-
-    def tearDown(self):
-        self.loop.run_until_complete(self.gc.close())
-        self.loop.close()
-
-    def test_session(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            results = yield from self.gc.execute(self.script2)
-            return results
-
-        results = self.loop.run_until_complete(go())
-        self.assertEqual(results[0].data[0]['value'], 'Dave')
-
-    def test_session_reset(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            self.gc.reset_session()
-            results = yield from self.gc.execute(self.script2)
-            return results
-        try:
-            results = self.loop.run_until_complete(go())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-    def test_session_manual_reset(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            new_sess = str(uuid.uuid4())
-            sess = self.gc.reset_session(session=new_sess)
-            self.assertEqual(sess, new_sess)
-            self.assertEqual(self.gc.session, new_sess)
-            results = yield from self.gc.execute(self.script2)
-            return results
-        try:
-            results = self.loop.run_until_complete(go())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-    def test_session_set(self):
-
-        @asyncio.coroutine
-        def go():
-            yield from self.gc.execute(self.script1)
-            new_sess = str(uuid.uuid4())
-            self.gc.session = new_sess
-            self.assertEqual(self.gc.session, new_sess)
-            results = yield from self.gc.execute(self.script2)
-            return results
-        try:
-            results = self.loop.run_until_complete(go())
-            error = False
-        except GremlinServerError:
-            error = True
-        self.assertTrue(error)
-
-    def test_resp_session(self):
-
-        @asyncio.coroutine
-        def go():
-            session = str(uuid.uuid4())
-            self.gc.session = session
-            resp = yield from self.gc.submit("x + x", bindings={"x": 4})
-            while True:
-                f = yield from resp.stream.read()
-                if f is None:
-                    break
-            self.assertEqual(resp.session, session)
-
-        self.loop.run_until_complete(go())
-
-
-if __name__ == "__main__":
-    unittest.main()