Open thorwhalen opened 3 years ago
Use factory methods to create the view classes instead (Gang of Four design patterns, not suprisingly, calls this the : Factory method pattern):
class BaseMapping:
# factories for mapping view objects
# that subclasses can replace
KeysView = BaseKeysView
ValuesView = BaseValuesView
ItemsView = BaseItemsView
def keys(self):
# each of these methods use the factory method on self,
# here that's self.KeysView(), and expect it to take specific arguments.
return self.KeysView(self)
def values(self):
return self.ValuesView(self)
def items(self):
return self.ItemsView(self)
class SpecialKeysView(BaseMapping.KeysView): # or SpecialKeysView(BaseKeysView)
def extra_method(self):
# ...
class SpecialMapping:
KeysView = SpecialKeysView
# ...
sm = SpecialMapping()
type(sm.keys()) # will be SpecialKeysView
If your subclassed factories need to accept extra arguments, you could use a partial()
, or have the __init__
method pull
in more information from the standard context that is passed in (in the above examples, BaseMapping.keys()
passes in the
mapping object, self
, to each factory call).
Tests in mongodol/tests/not_working.py:test_mongo_values_view_when_wrapping
Attempt at the above (still not working):
from collections import Mapping
from py2store import KvReader
from collections import (
KeysView as BaseKeysView,
ValuesView as BaseValuesView,
ItemsView as BaseItemsView,
)
class BaseMapping(dict):
# factories for mapping view objects
# that subclasses can replace
KeysView = BaseKeysView
ValuesView = BaseValuesView
ItemsView = BaseItemsView
def keys(self):
# each of these methods use the factory method on self,
# here that's self.KeysView(), and expect it to take specific arguments.
return self.KeysView(self)
def values(self):
return self.ValuesView(self)
def items(self):
return self.ItemsView(self)
class SpecialValuesView(BaseKeysView): # or SpecialKeysView(BaseKeysView)
def distinct(self):
return set(v for k, v in self._mapping.items()) # TODO: How to use super values() to get values?
class SpecialMapping(BaseMapping):
KeysView = SpecialKeysView
ValuesView = SpecialValuesView
from py2store import wrap_kvs
t = SpecialMapping(a=1, b=2, c=1)
assert str(type(sm.keys())) == "<class '__main__.SpecialKeysView'>"
t.values().distinct() == {1, 2}
# But...
tt = wrap_kvs(t)
assert str(type(tt.values())) == "<class 'collections.abc.ValuesView'>" # TODO: Needs to be SpecialKeysView!!!
# And same for type wrapping:
TTT = wrap_kvs(SpecialMapping)
ttt = TTT(a=1, b=2, c=1)
assert str(type(ttt.values())) == "<class 'collections.abc.ValuesView'>" # TODO: Needs to be SpecialKeysView!!!
Had the problem that the special
values()
, returning aMongoValuesView
, wasn't being carried over when wrapped (bykv_wrap
: https://github.com/i2mint/mongodol/blob/de97a7e36e591bbc9d82885b8c1626e2cd9e048a/mongodol/base.py#L90To hack it through, did this: https://github.com/i2mint/py2store/commit/3dbdb04f590e701790154c14fa9808b3a0958f8f
Which worked:
But...
Resolved by taking
distinct
out ofMongoValuesView
. It seems it's better that way, but it also sheds light on the limitations of the wrapping mechanism.