Package: txaioetcd
txaioetcdis anobject-relational remote persistant map layerbacked by etcd.It also provides a low-level asynchronous API for general Twisted etcd applications, bypassing
the object-relational layer of the library.InstallationThe implementation is pure Python code compatible with bothPython 2 and 3and runs perfect onPyPy.
On the server-side,etcd version 3.1 or higheris required. To install txaioetcdpipinstalltxaioetcdNoteThe library currently requiresTwisted, though the API was designed to allow adding asyncio support later (PRs are welcome!) with no breakage.
But other than the underlying network library, there are only small pure Python dependencies.
etcd 2 will not work. etcd 3.0 also isn’t enough - at least watching keys doesn’t work over the gRPC HTTP gateway yet.Getting StartedGet the complete example source code for the getting started below fromhere.To start withtxaioetcdusing the high-level, remote persistent map API,
define at least one class for data to be persisted,
eg aUser class:classUser(object):defmarshal(self):"""
        Marshal the object into a generic host language object.
        """@staticmethoddefunmarshal(obj):"""
        Parse a generic host language object into a native object of this class.
        """Then define a table for a slot to be used with key-value stores:fromtxaioetcdimportpmap# users table schema (a table with UUID keys and CBOR values holding User objects)tab_users=pmap.MapUuidCbor(1,marshal=lambdauser:user.marshal(),unmarshal=User.unmarshal)Above will define a table slot (with index 1) that has UUIDs for keys, and CBOR serialized
objects of User class for values.NoteThe User class does not appear literally, but only the “marshal” and “unmarshal”
parameters to the persistant map type specifies the object interface of the user class
to the persistant map library. The application developers needs to provide implementations of
the respective application class marshal/unmarshal interface.The available types for keys and values of persistant maps include:String (UTF8), egMapUuidString,MapStringString,MapStringUuid, ..Binary, egMapUuidBinary,MapStringBinary, ..OID (uint64), egMapUuidOid,MapOidCbor, ..UUID (uint128), egMapUuidCbor,MapUuidUuid, ..JSON, egMapUuidJson,MapOidJson,MapStringJson, ..CBOR, egMapOidCbor,MapUuidCbor,MapStringCbor, ..Pickle (Python), egMapStringPickle, ..Flatbuffers, egMapUuidFlatbuffers, ..For example, the following is another valid slot definition:# users table schema (a table with OID keys and Python Pickle values holding User objects)tab_users=pmap.MapOidPickle(2,marshal=lambdauser:user.marshal(),unmarshal=User.parse)Above will define a table slot (with index 2) that has OIDs for keys, and Python Pickle serialized
objects of User class for values.ConnectingFirst open a connection to etcd as a backing store:fromtxaioetcdimportClient,Databaseetcd=Client(reactor,url='http://localhost:2379')db=Database(etcd)To check the database connection:revision=awaitdb.status()print('connected to etcd: revision',revision)Storing and loading objectsNow create a native Python object from the class above and store it in the table, that is remotely in etcd:user=User()user.name='foobar'user.oid=uuid.uuid4()# create an async writable transaction to modify etcd dataasyncwithdb.begin(write=True)astxn:tab_users[txn,user.oid]=user# data is committed when transaction leaves scope .. hereprint('user stored:{}'.format(user))Load a native Python object from the table, that is remotely from etcd:# create an async read-only transaction when only accessing data in etcdasyncwithdb.begin()astxn:user=awaittab_users[txn,user.oid]print('user loaded:{}'.format(user))Putting it togetherTo put all the pieces together and run the code, you might use the following boilerplateimporttxaiotxaio.use_twisted()fromtwisted.internet.taskimportreactfromtwisted.internet.deferimportensureDeferredfromtxaioetcdimportClient,Databaseasyncdefmain(reactor):etcd=Client(reactor,url='http://localhost:2379')db=Database()revision=awaitdb.status()print('connected to etcd: revision',revision)# INSERT YOUR CODE HEREdef_main():returnreact(lambdareactor:ensureDeferred(main(reactor)))if__name__=='__main__':txaio.start_logging(level='info')_main()Insert your code to operate on etcd in above placeholder.