From a7b926625fb5ed44d42a4db660e578d9ddb97098 Mon Sep 17 00:00:00 2001 From: davebshow <davebshow@gmail.com> Date: Mon, 27 Apr 2015 23:34:12 -0400 Subject: [PATCH] preparing for more refactoring, clean ups, error handling etc --- README.md | 6 ++--- aiogremlin/__init__.py | 2 +- aiogremlin/abc.py | 26 ++++++++------------ aiogremlin/connection.py | 52 +++++++++++++++++++++++++++++++++------- aiogremlin/protocol.py | 1 + aiogremlin/response.py | 5 ++-- aiogremlin/tasks.py | 1 + 7 files changed, 62 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 1c3d412..8f5db31 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@ Fire up the Gremlin Server: $ ./bin/gremlin-server.sh ``` -The `AsyncGremlinClient` communicates asynchronously with the Gremlin Server using websockets. The client uses a combination of [asyncio.coroutine](https://docs.python.org/3/library/asyncio-task.html#coroutines) and [asyncio.Task](https://docs.python.org/3/library/asyncio-task.html#task) run on Asyncio's pluggable event loop to achieve this communication. +The `GremlinClient` communicates asynchronously with the Gremlin Server using websockets. The client uses a combination of [asyncio.coroutine](https://docs.python.org/3/library/asyncio-task.html#coroutines) and [asyncio.Task](https://docs.python.org/3/library/asyncio-task.html#task) run on Asyncio's pluggable event loop to achieve this communication. -The majority of ``AsyncGremlinClient`` methods are an `asyncio.coroutine`, so you will also need to use either `asyncio` or the `aiogremlin` [Task API](#task-api). The following examples use `asyncio` to demonstrate the use of the AsyncioGremlineClient. +The majority of `GremlinClient` methods are an `asyncio.coroutine`, so you will also need to use either `asyncio` or the `aiogremlin` [Task API](#task-api). The following examples use `asyncio` to demonstrate the use of the AsyncioGremlineClient. -The Gremlin Server sends responses in chunks, so `AsyncGremlinClient.submit` returns a list of gremlin response objects: +The Gremlin Server sends responses in chunks, so `GremlinClient.submit` returns a list of gremlin response objects: ```python >>> import asyncio diff --git a/aiogremlin/__init__.py b/aiogremlin/__init__.py index 00e596a..f462346 100644 --- a/aiogremlin/__init__.py +++ b/aiogremlin/__init__.py @@ -1,4 +1,4 @@ -from .abc import AbstractBaseFactory, AbstractBaseConnection +from .abc import AbstractFactory, AbstractConnection from .connection import WebsocketPool, AiohttpFactory from .client import GremlinClient from .contextmanager import GremlinContext diff --git a/aiogremlin/abc.py b/aiogremlin/abc.py index 851503c..b5c480d 100644 --- a/aiogremlin/abc.py +++ b/aiogremlin/abc.py @@ -1,8 +1,7 @@ -import asyncio from abc import ABCMeta, abstractmethod -class AbstractBaseFactory(metaclass=ABCMeta): +class AbstractFactory(metaclass=ABCMeta): @classmethod @abstractmethod @@ -10,30 +9,25 @@ class AbstractBaseFactory(metaclass=ABCMeta): pass @property + @abstractmethod def factory(self): - return self - + pass -class AbstractBaseConnection(metaclass=ABCMeta): - def __init__(self, socket, pool=None): - self.socket = socket - self._pool = pool +class AbstractConnection(metaclass=ABCMeta): + @abstractmethod def feed_pool(self): - if self.pool: - if self in self.pool.active_conns: - self.pool.feed_pool(self) + pass - @asyncio.coroutine + @abstractmethod def release(self): - yield from self.close() - if self in self.pool.active_conns: - self.pool.active_conns.discard(self) + pass @property + @abstractmethod def pool(self): - return self._pool + pass @property @abstractmethod diff --git a/aiogremlin/connection.py b/aiogremlin/connection.py index ed35dc6..a135bb6 100644 --- a/aiogremlin/connection.py +++ b/aiogremlin/connection.py @@ -4,7 +4,7 @@ import asyncio import aiohttp -from .abc import AbstractBaseFactory, AbstractBaseConnection +from .abc import AbstractFactory, AbstractConnection from .exceptions import SocketClientError from .log import INFO, conn_logger @@ -41,6 +41,8 @@ class WebsocketPool: return len(self.active_conns) def feed_pool(self, conn): + if self._closed: + raise RuntimeError("WebsocketPool is closed.") self.active_conns.discard(conn) self._put(conn) @@ -70,6 +72,8 @@ class WebsocketPool: @asyncio.coroutine def connect(self, uri=None, loop=None, num_retries=None): + if self._closed: + raise RuntimeError("WebsocketPool is closed.") if num_retries is None: num_retries = self.max_retries uri = uri or self.uri @@ -111,7 +115,14 @@ class WebsocketPool: pass -class AiohttpFactory(AbstractBaseFactory): +class BaseFactory(AbstractFactory): + + @property + def factory(self): + return self + + +class AiohttpFactory(BaseFactory): @classmethod @asyncio.coroutine @@ -128,13 +139,34 @@ class AiohttpFactory(AbstractBaseFactory): return AiohttpConnection(socket, pool) -class AiohttpConnection(AbstractBaseConnection): +class BaseConnection(AbstractConnection): def __init__(self, socket, pool=None): - super().__init__(socket, pool=pool) + self.socket = socket + self._pool = pool + + def feed_pool(self): + if self.pool: + if self in self.pool.active_conns: + self.pool.feed_pool(self) + + @asyncio.coroutine + def release(self): + try: + yield from self.close() + finally: + if self in self.pool.active_conns: + self.pool.active_conns.discard(self) + + @property + def pool(self): + return self._pool - def __str__(self): - return "{} wrapping {}".format(repr(self), repr(self.socket)) + +class AiohttpConnection(BaseConnection): + + def __init__(self, socket, pool=None): + super().__init__(socket, pool=pool) @property def closed(self): @@ -142,7 +174,11 @@ class AiohttpConnection(AbstractBaseConnection): @asyncio.coroutine def close(self): - yield from self.socket.close() + if not self.socket._closed: + try: + yield from self.socket.close() + finally: + self._closed = True @asyncio.coroutine def send(self, message, binary=True): @@ -189,7 +225,7 @@ class AiohttpConnection(AbstractBaseConnection): elif message.tp == aiohttp.MsgType.error: raise SocketClientError(self.socket.exception()) elif message.tp == aiohttp.MsgType.closed: - raise SocketClientError("Socket closed.") + raise RuntimeError("Socket closed.") break finally: yield from self.release() diff --git a/aiogremlin/protocol.py b/aiogremlin/protocol.py index 3b46797..4f10ec3 100644 --- a/aiogremlin/protocol.py +++ b/aiogremlin/protocol.py @@ -27,6 +27,7 @@ def gremlin_response_parser(connection): finally: yield from connection.release() + class GremlinWriter: def __init__(self, connection): diff --git a/aiogremlin/response.py b/aiogremlin/response.py index d6e3808..04a9944 100644 --- a/aiogremlin/response.py +++ b/aiogremlin/response.py @@ -1,10 +1,9 @@ """ -gizmo.response - -This module defines parsers for the Gremlin Server response. +THIS MODULE WILL BE REMOVED """ class GremlinResponse(list): + def __init__(self, message): """ A subclass of list that parses and flattens the Gremlin Server's diff --git a/aiogremlin/tasks.py b/aiogremlin/tasks.py index 92218f2..562d173 100644 --- a/aiogremlin/tasks.py +++ b/aiogremlin/tasks.py @@ -1,4 +1,5 @@ """ +THIS MODULE WILL BE COMPLETELY REFACTORED """ import asyncio import itertools -- GitLab