From c14bae60505d23b3151e9914d56df44c43646315 Mon Sep 17 00:00:00 2001
From: Noah Levitt <nlevitt@archive.org>
Date: Wed, 1 Mar 2017 11:20:27 -0800
Subject: [PATCH] new convention, call Rethinker object `rr` (mnemonic
 RethinkeR, or *double*[think]), leave rethinkdb as `r` per the rethinkdb
 convention

---
 README.rst               |  14 ++---
 doublethink/orm.py       |  26 ++++-----
 doublethink/rethinker.py |  16 +++---
 doublethink/services.py  |  28 +++++-----
 setup.py                 |   2 +-
 tests/test_rethinker.py  | 114 +++++++++++++++++++--------------------
 6 files changed, 100 insertions(+), 100 deletions(-)

diff --git a/README.rst b/README.rst
index 646e816..c77f05b 100644
--- a/README.rst
+++ b/README.rst
@@ -25,9 +25,9 @@ Usage Example
 ::
 
     import doublethink
-    r = doublethink.Rethinker(['db0.foo.com', 'db0.foo.com:38015', 'db1.foo.com'], 'my_db')
-    r.table('mytable').insert({'foo':'bar','baz':2}).run()
-    for result in r.table('mytable'):
+    rr = doublethink.Rethinker(['db0.foo.com', 'db0.foo.com:38015', 'db1.foo.com'], 'my_db')
+    rr.table('mytable').insert({'foo':'bar','baz':2}).run()
+    for result in rr.table('mytable'):
         print("result={}".format(result))
 
 ORM
@@ -42,16 +42,16 @@ Usage Example
 
     import doublethink
 
-    r = doublethink.Rethinker(['db0.foo.com', 'db0.foo.com:38015', 'db1.foo.com'], 'my_db')
+    rr = doublethink.Rethinker(['db0.foo.com', 'db0.foo.com:38015', 'db1.foo.com'], 'my_db')
 
     class MyTable(doublethink.Document):
         pass
-    MyTable.table_create()
+    MyTable.table_create(rr)
 
-    doc1 = MyTable(r, {'animal': 'elephant', 'size': 'large'})
+    doc1 = MyTable(rr, {'animal': 'elephant', 'size': 'large'})
     doc1.save()
 
-    doc1_copy = MyTable.get(r, doc1.id)
+    doc1_copy = MyTable.get(rr, doc1.id)
     doc1_copy.food = 'bread'
     doc1_copy.save()
 
diff --git a/doublethink/orm.py b/doublethink/orm.py
index c264f2f..be4452c 100644
--- a/doublethink/orm.py
+++ b/doublethink/orm.py
@@ -158,25 +158,25 @@ class Document(dict, object):
         return cls.__name__.lower()
 
     @classmethod
-    def load(cls, rethinker, pk):
+    def load(cls, rr, pk):
         '''
         Retrieves a document from the database, by primary key.
         '''
-        doc = cls(rethinker)
+        doc = cls(rr)
         doc[doc.pk_field] = pk
         doc.refresh()
         return doc
 
     @classmethod
-    def table_create(cls, rethinker):
+    def table_create(cls, rr):
         '''
         Creates the table. Subclasses may want to override this method to do
         more things, such as creating secondary indexes.
         '''
-        rethinker.table_create(cls.table).run()
+        rr.table_create(cls.table).run()
 
-    def __init__(self, rethinker, d={}):
-        self._r = rethinker
+    def __init__(self, rr, d={}):
+        dict.__setattr__(self, 'rr', rr)
         self._pk = None
         self._clear_updates()
         for k in d:
@@ -235,14 +235,14 @@ class Document(dict, object):
         '''
         if not self._pk:
             try:
-                pk = self._r.db('rethinkdb').table('table_config').filter({
-                    'db': self._r.dbname, 'name': self.table}).get_field(
+                pk = self.rr.db('rethinkdb').table('table_config').filter({
+                    'db': self.rr.dbname, 'name': self.table}).get_field(
                             'primary_key')[0].run()
                 self._pk = pk
             except Exception as e:
                 raise Exception(
                         'problem determining primary key for table %s.%s: %s',
-                        self._r.dbname, self.table, e)
+                        self.rr.dbname, self.table, e)
         return self._pk
 
     @property
@@ -270,7 +270,7 @@ class Document(dict, object):
                 # r.literal() to replace, not merge with, nested fields
                 updates = {field: r.literal(self._updates[field])
                            for field in self._updates}
-                query = self._r.table(self.table).get(
+                query = self.rr.table(self.table).get(
                         self.pk_value).update(updates)
                 result = query.run()
                 if result['skipped']:  # primary key not found
@@ -280,7 +280,7 @@ class Document(dict, object):
                             'unexpected result %s from rethinkdb query %s' % (
                                 result, query))
             if not should_insert and self._deletes:
-                query = self._r.table(self.table).replace(
+                query = self.rr.table(self.table).replace(
                         r.row.without(self._deletes))
                 result = query.run()
                 if result['errors']:   # primary key not found
@@ -293,7 +293,7 @@ class Document(dict, object):
             should_insert = True
 
         if should_insert:
-            query = self._r.table(self.table).insert(self)
+            query = self.rr.table(self.table).insert(self)
             result = query.run()
             if result['inserted'] != 1:
                     raise Exception(
@@ -309,7 +309,7 @@ class Document(dict, object):
         '''
         Refresh the document from the database.
         '''
-        d = self._r.table(self.table).get(self.pk_value).run()
+        d = self.rr.table(self.table).get(self.pk_value).run()
         if d is None:
             raise KeyError
         for k in d:
diff --git a/doublethink/rethinker.py b/doublethink/rethinker.py
index 277d874..b0135c7 100644
--- a/doublethink/rethinker.py
+++ b/doublethink/rethinker.py
@@ -24,16 +24,16 @@ import types
 
 class RethinkerWrapper(object):
     logger = logging.getLogger('doublethink.RethinkerWrapper')
-    def __init__(self, rethinker, wrapped):
-        self.rethinker = rethinker
+    def __init__(self, rr, wrapped):
+        self.rr = rr
         self.wrapped = wrapped
 
     def __getattr__(self, name):
         delegate = getattr(self.wrapped, name)
-        return self.rethinker.wrap(delegate)
+        return self.rr.wrap(delegate)
 
     def __getitem__(self, key):
-        return self.rethinker.wrap(self.wrapped.__getitem__)(key)
+        return self.rr.wrap(self.wrapped.__getitem__)(key)
 
     def __repr__(self):
         return '<RethinkerWrapper{}>'.format(repr(self.wrapped))
@@ -41,10 +41,10 @@ class RethinkerWrapper(object):
     def run(self, db=None):
         self.wrapped.run  # raise AttributeError early
         while True:
-            conn = self.rethinker._random_server_connection()
+            conn = self.rr._random_server_connection()
             is_iter = False
             try:
-                result = self.wrapped.run(conn, db=db or self.rethinker.dbname)
+                result = self.wrapped.run(conn, db=db or self.rr.dbname)
                 if hasattr(result, '__next__'):
                     is_iter = True
                     def gen():
@@ -72,8 +72,8 @@ class RethinkerWrapper(object):
 
 class Rethinker(object):
     '''
-    >>> r = Rethinker(db='my_db')
-    >>> doc = r.table('my_table').get(1).run()
+    >>> rr = Rethinker(db='my_db')
+    >>> doc = rr.table('my_table').get(1).run()
     '''
     logger = logging.getLogger('doublethink.Rethinker')
 
diff --git a/doublethink/services.py b/doublethink/services.py
index 4786e91..c1cfc8b 100644
--- a/doublethink/services.py
+++ b/doublethink/services.py
@@ -39,20 +39,20 @@ class ServiceRegistry(object):
 
     logger = logging.getLogger('doublethink.ServiceRegistry')
 
-    def __init__(self, rethinker):
-        self.r = rethinker
+    def __init__(self, rr):
+        self.rr = rr
         self._ensure_table()
 
     def _ensure_table(self):
-        dbs = self.r.db_list().run()
-        if not self.r.dbname in dbs:
-            self.logger.info('creating rethinkdb database %s', repr(self.r.dbname))
-            self.r.db_create(self.r.dbname).run()
-        tables = self.r.table_list().run()
+        dbs = self.rr.db_list().run()
+        if not self.rr.dbname in dbs:
+            self.logger.info('creating rethinkdb database %s', repr(self.rr.dbname))
+            self.rr.db_create(self.rr.dbname).run()
+        tables = self.rr.table_list().run()
         if not 'services' in tables:
-            self.logger.info("creating rethinkdb table 'services' in database %s", repr(self.r.dbname))
-            self.r.table_create('services', shards=1, replicas=min(3, len(self.r.servers))).run()
-            # self.r.table('sites').index_create...?
+            self.logger.info("creating rethinkdb table 'services' in database %s", repr(self.rr.dbname))
+            self.rr.table_create('services', shards=1, replicas=min(3, len(self.rr.servers))).run()
+            # self.rr.table('sites').index_create...?
 
     def heartbeat(self, status_info):
         '''
@@ -68,7 +68,7 @@ class ServiceRegistry(object):
         if not 'pid' in updated_status_info:
             updated_status_info['pid'] = os.getpid()
         try:
-            result = self.r.table('services').insert(
+            result = self.rr.table('services').insert(
                     updated_status_info, conflict='replace',
                     return_changes=True).run()
             return result['changes'][0]['new_val'] # XXX check
@@ -77,13 +77,13 @@ class ServiceRegistry(object):
             return status_info
 
     def unregister(self, id):
-        result = self.r.table('services').get(id).delete().run()
+        result = self.rr.table('services').get(id).delete().run()
         if result != {'deleted':1,'errors':0,'inserted':0,'replaced':0,'skipped':0,'unchanged':0}:
             self.logger.warn('unexpected result attempting to delete id=%s from rethinkdb services table: %s', id, result)
 
     def available_service(self, role):
         try:
-            result = self.r.table('services').filter({"role":role}).filter(
+            result = self.rr.table('services').filter({"role":role}).filter(
                 lambda svc: r.now().sub(svc["last_heartbeat"]) < 3 * svc["heartbeat_interval"]   #.default(20.0)
             ).order_by("load")[0].run()
             return result
@@ -92,7 +92,7 @@ class ServiceRegistry(object):
 
     def available_services(self, role=None):
         try:
-            query = self.r.table('services')
+            query = self.rr.table('services')
             if role:
                 query = query.filter({"role":role})
             query = query.filter(
diff --git a/setup.py b/setup.py
index ab1d077..fe3da61 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@ import codecs
 
 setuptools.setup(
     name='doublethink',
-    version='0.2.0.dev65',
+    version='0.2.0.dev66',
     packages=['doublethink'],
     classifiers=[
         'Programming Language :: Python :: 2.7',
diff --git a/tests/test_rethinker.py b/tests/test_rethinker.py
index 5ba6295..3ad3487 100644
--- a/tests/test_rethinker.py
+++ b/tests/test_rethinker.py
@@ -22,7 +22,7 @@ import sys
 import types
 import gc
 import pytest
-import rethinkdb
+import rethinkdb as r
 import time
 import socket
 import os
@@ -41,82 +41,82 @@ class RethinkerForTesting(doublethink.Rethinker):
         return self.last_conn
 
 @pytest.fixture(scope="module")
-def r():
-    r = RethinkerForTesting()
+def rr():
+    rr = RethinkerForTesting()
     try:
-        r.db_drop("doublethink_test_db").run()
-    except rethinkdb.errors.ReqlOpFailedError:
+        rr.db_drop("doublethink_test_db").run()
+    except r.errors.ReqlOpFailedError:
         pass
-    result = r.db_create("doublethink_test_db").run()
-    assert not r.last_conn.is_open()
+    result = rr.db_create("doublethink_test_db").run()
+    assert not rr.last_conn.is_open()
     assert result["dbs_created"] == 1
     return RethinkerForTesting(db="doublethink_test_db")
 
 @pytest.fixture(scope="module")
-def my_table(r):
-    assert r.table_list().run() == []
-    result = r.table_create("my_table").run()
-    assert not r.last_conn.is_open()
+def my_table(rr):
+    assert rr.table_list().run() == []
+    result = rr.table_create("my_table").run()
+    assert not rr.last_conn.is_open()
     assert result["tables_created"] == 1
 
-def test_rethinker(r, my_table):
-    assert r.table("my_table").index_create("foo").run() == {"created": 1}
-    assert not r.last_conn.is_open()
+def test_rethinker(rr, my_table):
+    assert rr.table("my_table").index_create("foo").run() == {"created": 1}
+    assert not rr.last_conn.is_open()
 
-    result = r.table("my_table").insert(({"foo":i,"bar":"repeat"*i} for i in range(2000))).run()
-    assert not r.last_conn.is_open()
+    result = rr.table("my_table").insert(({"foo":i,"bar":"repeat"*i} for i in range(2000))).run()
+    assert not rr.last_conn.is_open()
     assert len(result["generated_keys"]) == 2000
     assert result["inserted"] == 2000
 
-    result = r.table("my_table").run()
-    assert r.last_conn.is_open() # should still be open this time
+    result = rr.table("my_table").run()
+    assert rr.last_conn.is_open() # should still be open this time
     assert isinstance(result, types.GeneratorType)
     n = 0
     for x in result:
         n += 1
         pass
     # connection should be closed after finished iterating over results
-    assert not r.last_conn.is_open()
+    assert not rr.last_conn.is_open()
     assert n == 2000
 
-    result = r.table("my_table").run()
-    assert r.last_conn.is_open() # should still be open this time
+    result = rr.table("my_table").run()
+    assert rr.last_conn.is_open() # should still be open this time
     assert isinstance(result, types.GeneratorType)
     next(result)
     result = None
     gc.collect()
     # connection should be closed after result is garbage-collected
-    assert not r.last_conn.is_open()
+    assert not rr.last_conn.is_open()
 
-    result = r.table("my_table").run()
-    assert r.last_conn.is_open() # should still be open this time
+    result = rr.table("my_table").run()
+    assert rr.last_conn.is_open() # should still be open this time
     assert isinstance(result, types.GeneratorType)
     result = None
     gc.collect()
     # connection should be closed after result is garbage-collected
-    assert not r.last_conn.is_open()
+    assert not rr.last_conn.is_open()
 
-def test_too_many_errors(r):
-    with pytest.raises(rethinkdb.errors.ReqlOpFailedError):
-        r.table_create("too_many_replicas", replicas=99).run()
-    with pytest.raises(rethinkdb.errors.ReqlOpFailedError):
-        r.table_create("too_many_shards", shards=99).run()
+def test_too_many_errors(rr):
+    with pytest.raises(r.errors.ReqlOpFailedError):
+        rr.table_create("too_many_replicas", replicas=99).run()
+    with pytest.raises(r.errors.ReqlOpFailedError):
+        rr.table_create("too_many_shards", shards=99).run()
 
-def test_slice(r, my_table):
+def test_slice(rr, my_table):
     """Tests RethinkerWrapper.__getitem__()"""
-    result = r.table("my_table")[5:10].run()
-    assert r.last_conn.is_open() # should still be open this time
+    result = rr.table("my_table")[5:10].run()
+    assert rr.last_conn.is_open() # should still be open this time
     assert isinstance(result, types.GeneratorType)
     n = 0
     for x in result:
         n += 1
         pass
     # connection should be closed after finished iterating over results
-    assert not r.last_conn.is_open()
+    assert not rr.last_conn.is_open()
     assert n == 5
 
-def test_service_registry(r):
-    svcreg = doublethink.ServiceRegistry(r)
+def test_service_registry(rr):
+    svcreg = doublethink.ServiceRegistry(rr)
     assert svcreg.available_service("yes-such-role") == None
     assert svcreg.available_services("yes-such-role") == []
     assert svcreg.available_services() == []
@@ -235,19 +235,19 @@ def test_service_registry(r):
     assert len(svcreg.available_services("yes-such-role")) == 2
     assert len(svcreg.available_services()) == 4
 
-def test_svcreg_heartbeat_server_down(r):
+def test_svcreg_heartbeat_server_down(rr):
     class MockRethinker:
         def table(self, *args, **kwargs):
             raise Exception('catch me if you can')
 
     class SortOfFakeServiceRegistry(doublethink.ServiceRegistry):
         def __init__(self, rethinker):
-            self.r = rethinker
+            self.rr = rethinker
             # self._ensure_table() # not doing this here
 
     # no such rethinkdb server
-    r = MockRethinker()
-    svcreg = SortOfFakeServiceRegistry(r)
+    rr = MockRethinker()
+    svcreg = SortOfFakeServiceRegistry(rr)
     svc0 = {
         "role": "role-foo",
         "load": 100.0,
@@ -279,19 +279,19 @@ def test_utcnow():
 
     ## XXX what else can we test without jumping through hoops?
 
-def test_orm(r):
+def test_orm(rr):
     class SomeDoc(doublethink.Document):
         table = 'some_doc'
 
-    SomeDoc.table_create(r)
+    SomeDoc.table_create(rr)
     with pytest.raises(Exception):
-        SomeDoc.table_create(r)
+        SomeDoc.table_create(rr)
 
     # test that overriding Document.table works
-    assert 'some_doc' in r.table_list().run()
-    assert not 'somedoc' in r.table_list().run()
+    assert 'some_doc' in rr.table_list().run()
+    assert not 'somedoc' in rr.table_list().run()
 
-    d = SomeDoc(rethinker=r, d={
+    d = SomeDoc(rr, d={
         'a': 'b',
         'c': {'d': 'e'},
         'f': ['g', 'h'],
@@ -410,7 +410,7 @@ def test_orm(r):
     assert d._updates == {}
     assert d._deletes == set()
 
-    d_copy = SomeDoc.load(r, d.id)
+    d_copy = SomeDoc.load(rr, d.id)
     assert d == d_copy
     d['zuh'] = 'toot'
     d.save()
@@ -450,7 +450,7 @@ def test_orm(r):
     assert d._updates == {}
     assert d._deletes == set()
 
-    d_copy = SomeDoc.load(r, d.id)
+    d_copy = SomeDoc.load(rr, d.id)
     assert d == d_copy
     d['yuh'] = 'soot'
     d.save()
@@ -458,19 +458,19 @@ def test_orm(r):
     d_copy.refresh()
     assert d == d_copy
 
-def test_orm_pk(r):
+def test_orm_pk(rr):
     class NonstandardPrimaryKey(doublethink.Document):
         @classmethod
         def table_create(cls, rethinker):
             rethinker.table_create(cls.table, primary_key='not_id').run()
 
     with pytest.raises(Exception):
-        NonstandardPrimaryKey.load(r, 'no_such_thing')
+        NonstandardPrimaryKey.load(rr, 'no_such_thing')
 
-    NonstandardPrimaryKey.table_create(r)
+    NonstandardPrimaryKey.table_create(rr)
 
     # new empty doc
-    f = NonstandardPrimaryKey(r, {})
+    f = NonstandardPrimaryKey(rr, {})
     f.save()
     assert f.pk_value
     assert 'not_id' in f
@@ -478,19 +478,19 @@ def test_orm_pk(r):
     assert len(f.keys()) == 1
 
     with pytest.raises(KeyError):
-        NonstandardPrimaryKey.load(r, 'no_such_thing')
+        NonstandardPrimaryKey.load(rr, 'no_such_thing')
 
     # new doc with (only) primary key
-    d = NonstandardPrimaryKey(r, {'not_id': 1})
+    d = NonstandardPrimaryKey(rr, {'not_id': 1})
     assert d.not_id == 1
     assert d.pk_value == 1
     d.save()
 
-    d_copy = NonstandardPrimaryKey.load(r, 1)
+    d_copy = NonstandardPrimaryKey.load(rr, 1)
     assert d == d_copy
 
     # new doc with something in it
-    e = NonstandardPrimaryKey(r, {'some_field': 'something'})
+    e = NonstandardPrimaryKey(rr, {'some_field': 'something'})
     with pytest.raises(KeyError):
         e['not_id']
     assert e.not_id is None
@@ -498,7 +498,7 @@ def test_orm_pk(r):
     e.save()
     assert e.not_id
 
-    e_copy = NonstandardPrimaryKey.load(r, e.not_id)
+    e_copy = NonstandardPrimaryKey.load(rr, e.not_id)
     assert e == e_copy
     e_copy['blah'] = 'toot'
     e_copy.save()