diff --git a/sample_lego.py b/sample_lego.py index abf7df8..afd60c6 100644 --- a/sample_lego.py +++ b/sample_lego.py @@ -1,13 +1,13 @@ import asyncio from thingsdb.client import Client -from thingsdb.model import Collection, Thing, ThingStrict, Enum +from thingsdb.model import Collection, Thing, ThingStrict, Enum, EnumMember from thingsdb.util import event class Color(Enum): RED = "#f00" - BLUE = "#0f0" - GREEN = "#00f" + GREEN = "#0f0" + BLUE = "#00f" class Brick(Thing): @@ -53,13 +53,25 @@ async def example(): # ... now the collection will be watched for 100 seconds while True: await asyncio.sleep(3) + if lego and lego.bricks: + + print('Color:', Color.RED is lego.bricks[0].color) + print('Is Enum', isinstance(Color.GREEN, Enum)) + print('Is EnumMember', isinstance(Color.GREEN, EnumMember)) + print('Is Color', isinstance(Color.GREEN, Color)) + print('Is True', Color.GREEN == Color("#0f0")) + print('Is True', Color.GREEN == Color["GREEN"]) + print('Is True', getattr(Color, 'GREEN') == Color["GREEN"]) + print('Is True', Color.RED.value == lego.bricks[0].color.value) + print('Is True', Color.RED.value == lego.bricks[0].color._value) + brick = lego.bricks[0] await brick.emit('new-color', 'RED') break await lego.query('.bricks.push(Brick{});') - await asyncio.sleep(300) + await asyncio.sleep(5) finally: client.close() diff --git a/thingsdb/client/client.py b/thingsdb/client/client.py index a7294bb..9c95aba 100644 --- a/thingsdb/client/client.py +++ b/thingsdb/client/client.py @@ -13,6 +13,7 @@ from ..exceptions import ForbiddenError + _WATCH_MISSING = \ 'auto reconnect cannot act on node changes since `WATCH` privileges on ' \ 'the `@node` scope are missing' diff --git a/thingsdb/model/__init__.py b/thingsdb/model/__init__.py index 76bc6dc..a6c83cb 100644 --- a/thingsdb/model/__init__.py +++ b/thingsdb/model/__init__.py @@ -1,3 +1,4 @@ -from .collection import Collection from .enum import Enum +from .enummember import EnumMember +from .collection import Collection from .thing import Thing, ThingStrict, ThingHash diff --git a/thingsdb/model/enum.py b/thingsdb/model/enum.py index d4216f7..c48bf98 100644 --- a/thingsdb/model/enum.py +++ b/thingsdb/model/enum.py @@ -1,20 +1,43 @@ -from .member import Member +from .enummember import EnumMember _enums_lookup = {} # enums lookup by name -class Enum: + +class _GetAttr(type): + def __getitem__(cls, name): + for k, v in cls.__dict__.items(): + if k == name: + return v + raise KeyError(f'no member with name `{k}`') + + +class Enum(metaclass=_GetAttr): _visited = 0 # For build, 0=not visited, 1=new_type, 2=set_type, 3=build + def __new__(cls, *args): + if len(args) != 1: + return super().__new__(cls) + + value = args[0] + for v in cls.__dict__.values(): + if isinstance(v, EnumMember) and v._value == value: + return v + raise ValueError(f'no member with value `{value}`') + def __init_subclass__(cls, **kwargs): + if issubclass(cls, EnumMember): + return + cls._name = getattr(cls, '__NAME__', cls.__name__) cls._id = None + cls._memberclass = type(f'{cls._name}Member', (EnumMember, cls), {}) # upgrade attributes to member instances for k, v in cls.__dict__.items(): if k.startswith('_'): continue - setattr(cls, k, Member(cls._name, k, v)) + setattr(cls, k, cls._memberclass(cls._name, k, v)) # register for lookup by name _enums_lookup[cls._name] = cls @@ -22,9 +45,11 @@ def __init_subclass__(cls, **kwargs): @staticmethod def _update_enum(enums, data, convert): name = data['name'] - members = [Member(name, k, convert(v)) for k, v in data['members']] - enum = _enums_lookup.get(name) + cls = EnumMember if enum is None else enum._memberclass + + members = [cls(name, k, convert(v)) for k, v in data['members']] + if enum is not None: enum._id = data['enum_id'] for member in members: @@ -36,10 +61,12 @@ def _update_enum(enums, data, convert): def _upd_enum_add(enums, data, convert): members = enums[data['enum_id']] name = members[0]._enum_name - member = Member(name, data['name'], convert(data['value'])) + enum = _enums_lookup.get(name) + cls = EnumMember if enum is None else enum._memberclass + + member = cls(name, data['name'], convert(data['value'])) members.append(member) - enum = _enums_lookup.get(name) if enum is not None: setattr(enum, member.name, member) @@ -93,7 +120,9 @@ async def _new_type(cls, client, collection): if cls._visited > 0: return cls._visited += 1 - members = (m for m in cls.__dict__.values() if isinstance(m, Member)) + members = ( + m for m in cls.__dict__.values() + if isinstance(m, EnumMember)) query = f''' set_enum('{cls._name}', {{ {', '.join(f'{m.name}: {m.value!r}' for m in members)} diff --git a/thingsdb/model/enummember.py b/thingsdb/model/enummember.py new file mode 100644 index 0000000..723e606 --- /dev/null +++ b/thingsdb/model/enummember.py @@ -0,0 +1,25 @@ +class EnumMember: + + @property + def name(self): + return self._name + + @property + def value(self): + return self._value + + def __new__(cls, enum_name, name, value): + instance = object.__new__(cls) + instance._name = name + instance._value = value + instance._enum_name = enum_name + return instance + + def __repr__(self): + return f'{self._enum_name}{{{self._name}}}' + + def __eq__(self, other): + return self is other or self._value == other + + def __ne__(self, other): + return not self.__eq__(other) diff --git a/thingsdb/model/member.py b/thingsdb/model/member.py deleted file mode 100644 index ce640be..0000000 --- a/thingsdb/model/member.py +++ /dev/null @@ -1,16 +0,0 @@ -class Member: - def __init__(self, enum_name, name, value): - self._name = name - self._value = value - self._enum_name = enum_name - - @property - def name(self): - return self._name - - @property - def value(self): - return self._value - - def __repr__(self): - return f'{self._enum_name}{{{self._name}}}' diff --git a/thingsdb/util/convert.py b/thingsdb/util/convert.py index 0b7f2c6..c3a9904 100644 --- a/thingsdb/util/convert.py +++ b/thingsdb/util/convert.py @@ -11,4 +11,4 @@ def convert(arg): if isinstance(arg, (list, tuple)): return [convert(v) for v in arg] - return arg + return getattr(arg, '_value', arg) diff --git a/thingsdb/util/fmt.py b/thingsdb/util/fmt.py index 7f333d2..f551319 100644 --- a/thingsdb/util/fmt.py +++ b/thingsdb/util/fmt.py @@ -9,8 +9,6 @@ def _wrap(value, blobs): name = f'blob{idx}' blobs[name] = value return name - if isinstance(value, Member): - return value.name() if isinstance(value, dict): thing_id = value.get('#') if thing_id is None: diff --git a/thingsdb/version.py b/thingsdb/version.py index e2f45ae..7c9e66e 100644 --- a/thingsdb/version.py +++ b/thingsdb/version.py @@ -1 +1 @@ -__version__ = '0.6.5' +__version__ = '0.6.6'