The idea is to have:
- a synchronous ds/ library that can be called from either Python 2 or Python 3, and
 - an asynchronous ads/ library
 
ads/ is meant to be a wrapper around ds/. It is callable with the await/async syntax but makes synchronous calls to ds/.
While we have both Python 2 and 3 code using the datastore, Python 2 uses ds/ while Python 3 uses ads/. Moving a module to Python 3 means using the async syntax and using ads/ (even though it makes synchronous calls under the hood).
When everything is on Python 3, nothing is calling ds/. We can move all the ds/ code to ads/ and remove the synchronous transport layer (from ds) and the wrapper code (from ads). ads/ is now asynchronous and ds/ can disappear. We can even rename ads/ to ds/ after that.
The left-hand side can be called form Python 2 or form Python 3. The right-hand side is Python 3 only.
ds.Model._get() contains all the get logic that's not part of the transport layer (see the current Model.get() on master).
It's called form both ds.Model.get() and ads.Model.get(), which are just wrappers. The wrappers call _get() and make sure it uses the correct transport get().
So when you use ds/, it goes ds.Model.get() -> ds.Model._get() -> ds.get().
When you use ads/, it goes ads.Model.get() -> ds.Model._get() -> ads.get().
The actual logic is not duplicated because it lives in ds.Model._get(). When we stop using ds/, that logic can move to ads.Model.get(). Then the call goes ads.Model.get() -> ads.get() and it's all asynchronous.
$ python client.py
Model sync get()
Model base _get()
get() with key = my_key
Got a model with key=my_key
$ python client.py
Model async get()
Model base _get()
async get() with key = my_key
Got a model with key=my_key
Python docs:
People solving similar problems:
