Skip to content

Commit

Permalink
Use type for proxy classes, slots on Proxy and add watch_effect (#95)
Browse files Browse the repository at this point in the history
* Use type for creating proxy classes

* Move proxy db to its own file

* Move set proxy into its own file

* Move list proxy into its own file

* Move dict proxy into its own file

* Move Proxy and traps into their own files

* Move last bits out of observables file

* Use slots on Proxy for faster property access and smaller memory footprint

* Update lock file

* Add watch_effect

* Drop 3.8 from ci and bump version number

* Add test for watch effect with scheduler
  • Loading branch information
berendkleinhaneveld authored Nov 2, 2023
1 parent d95450f commit c4724a9
Show file tree
Hide file tree
Showing 20 changed files with 743 additions and 675 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ jobs:
fail-fast: false
matrix:
include:
- name: Linux py38
pyversion: '3.8'
- name: Linux py39
pyversion: '3.9'
- name: Linux py310
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Observ 👁

Observ is a Python port of [Vue.js](https://vuejs.org/)' [computed properties and watchers](https://v3.vuejs.org/api/basic-reactivity.html). It is event loop/framework agnostic and has only one pure-python dependency ([patchdiff](https://github.com/Korijn/patchdiff)) so it can be used in any project targeting Python >= 3.8.
Observ is a Python port of [Vue.js](https://vuejs.org/)' [computed properties and watchers](https://v3.vuejs.org/api/basic-reactivity.html). It is event loop/framework agnostic and has only one pure-python dependency ([patchdiff](https://github.com/Korijn/patchdiff)) so it can be used in any project targeting Python >= 3.9.

Observ provides the following two benefits for stateful applications:

Expand Down
6 changes: 3 additions & 3 deletions observ/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
__version__ = "0.10.0"
__version__ = "0.11.0"


from .observables import (
from .proxy import (
reactive,
readonly,
shallow_reactive,
shallow_readonly,
to_raw,
)
from .scheduler import scheduler
from .watcher import computed, watch
from .watcher import computed, watch, watch_effect
78 changes: 78 additions & 0 deletions observ/dict_proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from .proxy import Proxy, TYPE_LOOKUP
from .traps import construct_methods_traps_dict, trap_map, trap_map_readonly


dict_traps = {
"READERS": {
"copy",
"__eq__",
"__format__",
"__ge__",
"__gt__",
"__le__",
"__len__",
"__lt__",
"__ne__",
"__repr__",
"__sizeof__",
"__str__",
"keys",
"__or__",
"__ror__",
},
"KEYREADERS": {
"get",
"__contains__",
"__getitem__",
},
"ITERATORS": {
"items",
"values",
"__iter__",
"__reversed__",
},
"WRITERS": {
"update",
"__ior__",
},
"KEYWRITERS": {
"setdefault",
"__setitem__",
},
"DELETERS": {
"clear",
"popitem",
},
"KEYDELETERS": {
"pop",
"__delitem__",
},
}


class DictProxyBase(Proxy):
def _orphaned_keydeps(self):
return set(self.proxy_db.attrs(self)["keydep"].keys()) - set(self.target.keys())


def readonly_dict_proxy_init(self, target, shallow=False, **kwargs):
super(ReadonlyDictProxy, self).__init__(
target, shallow=shallow, **{**kwargs, "readonly": True}
)


DictProxy = type(
"DictProxy",
(DictProxyBase,),
construct_methods_traps_dict(dict, dict_traps, trap_map),
)
ReadonlyDictProxy = type(
"ReadonlyDictProxy",
(DictProxyBase,),
{
"__init__": readonly_dict_proxy_init,
**construct_methods_traps_dict(dict, dict_traps, trap_map_readonly),
},
)

TYPE_LOOKUP[dict] = (DictProxy, ReadonlyDictProxy)
73 changes: 73 additions & 0 deletions observ/list_proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from .proxy import Proxy, TYPE_LOOKUP
from .traps import construct_methods_traps_dict, trap_map, trap_map_readonly


list_traps = {
"READERS": {
"count",
"index",
"copy",
"__add__",
"__getitem__",
"__contains__",
"__eq__",
"__ge__",
"__gt__",
"__le__",
"__lt__",
"__mul__",
"__ne__",
"__rmul__",
"__len__",
"__repr__",
"__str__",
"__format__",
"__sizeof__",
},
"ITERATORS": {
"__iter__",
"__reversed__",
},
"WRITERS": {
"append",
"clear",
"extend",
"insert",
"pop",
"remove",
"reverse",
"sort",
"__setitem__",
"__delitem__",
"__iadd__",
"__imul__",
},
}


class ListProxyBase(Proxy):
pass


def readonly_list_proxy_init(self, target, shallow=False, **kwargs):
super(ReadonlyListProxy, self).__init__(
target, shallow=shallow, **{**kwargs, "readonly": True}
)


ListProxy = type(
"ListProxy",
(ListProxyBase,),
construct_methods_traps_dict(list, list_traps, trap_map),
)
ReadonlyListProxy = type(
"ReadonlyListProxy",
(ListProxyBase,),
{
"__init__": readonly_list_proxy_init,
**construct_methods_traps_dict(list, list_traps, trap_map_readonly),
},
)


TYPE_LOOKUP[list] = (ListProxy, ReadonlyListProxy)
Loading

0 comments on commit c4724a9

Please sign in to comment.