Skip to content

Commit a9bff7d

Browse files
committed
Make it possible to use dot notation for setting context in reflex
In an effort to improve the api for setting the context that is used in the final context in the reflex we introduce a dot notation for setting the context. Ie `reflex.context.my_context = 'value'`. For the old way of setting the context in instance variables you now also prevented to set an instance variable that is already used by the reflex.
1 parent 23f5bf4 commit a9bff7d

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

sockpuppet/consumer.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,14 @@ def render_page(self, reflex):
235235
reflex_context = {key: getattr(reflex, key) for key in instance_variables}
236236
reflex_context["stimulus_reflex"] = True
237237

238+
if not reflex.context._attr_data:
239+
msg = (
240+
"Setting context through instance variables is deprecated, "
241+
'please use reflex.context.context_variable = "my_data"'
242+
)
243+
logger.warning(msg)
244+
reflex_context.update(reflex.context)
245+
238246
original_context_data = view.view_class.get_context_data
239247
reflex.get_context_data(**reflex_context)
240248
# monkey patch context method

sockpuppet/reflex.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,65 @@
1+
from collections import UserDict
12
from django.urls import resolve
23
from urllib.parse import urlparse
34

45
from django.test import RequestFactory
56

67
PROTECTED_VARIABLES = [
78
"consumer",
9+
"context",
810
"element",
11+
"params",
912
"selectors",
1013
"session",
1114
"url",
1215
]
1316

1417

18+
class Context(UserDict):
19+
"""
20+
A dictionary that keeps track of whether it's been used as dictionary
21+
or if values has been set with dot notation. We expect things to be set
22+
in dot notation so a warning is issued until next major version (1.0)
23+
"""
24+
25+
def __init__(self, *args, **kwargs):
26+
super().__init__(*args, **kwargs)
27+
self._attr_data = {}
28+
29+
def __getitem__(self, key):
30+
if not self.data.get(key) and not self._attr_data.get(key):
31+
raise KeyError(key)
32+
return self.data.get(key) or self._attr_data.get(key)
33+
34+
def __getattr__(self, key):
35+
if not self.data.get(key) and not self._attr_data.get(key):
36+
raise AttributeError(key)
37+
return self.data.get(key) or self._attr_data.get(key)
38+
39+
def __setattr__(self, key, value):
40+
self._attr_data[key] = value
41+
42+
1543
class Reflex:
1644
def __init__(self, consumer, url, element, selectors, params):
1745
self.consumer = consumer
18-
self.url = url
46+
self.context = Context()
1947
self.element = element
48+
self.params = params
2049
self.selectors = selectors
2150
self.session = consumer.scope["session"]
22-
self.params = params
23-
self.context = {}
51+
self.url = url
52+
53+
self._init_run = True
2454

2555
def __repr__(self):
2656
return f"<Reflex url: {self.url}, session: {self.get_channel_id()}>"
2757

58+
def __setattr__(self, name, value):
59+
if name in PROTECTED_VARIABLES and getattr(self, "_init_run", None):
60+
raise ValueError("This instance variable is used by the reflex.")
61+
super().__setattr__(name, value)
62+
2863
def get_context_data(self, *args, **kwargs):
2964
if self.context:
3065
self.context.update(**kwargs)
@@ -45,7 +80,7 @@ def get_context_data(self, *args, **kwargs):
4580

4681
context = view.get_context_data(**{"stimulus_reflex": True})
4782

48-
self.context = context
83+
self.context.update(context)
4984
self.context.update(**kwargs)
5085
return self.context
5186

0 commit comments

Comments
 (0)