Skip to content

Commit 0844177

Browse files
committed
updated readme, fixed a bug in repr
1 parent f7c34d9 commit 0844177

File tree

4 files changed

+42
-22
lines changed

4 files changed

+42
-22
lines changed

README.md

+39-19
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ template = Template(
9898

9999
# Now we can use the template in combination with the Endpoint:
100100

101-
from ops import CharmBase
102-
from endpoint_wrapper import Endpoint, ValidationError
101+
from ops.charm import CharmBase
102+
from endpoint_wrapper import Endpoint, ValidationError, databag_valid, validate_databag
103103

104104
class MyCharm(CharmBase):
105105
META = {'requires': {'foo': {'interface': 'bar'}}}
@@ -108,24 +108,24 @@ class MyCharm(CharmBase):
108108
super().__init__(*args)
109109
self.foo = Endpoint(
110110
self, 'foo',
111-
template=template,
112-
# we can omit `role` and it will be guessed from META, but if we do
113-
# provide it, we get nice type hints below
114-
role='requirer',
111+
requirer_template=template,
115112
on_changed=self._on_foo_changed
116113
)
117114

118115
# We are the requirer, and our template says that the local app data
119116
# model for the requirer is RequirerAppModel; so we expect
120-
# local_app_data to be a DataWrapper[RequirerAppModel]
117+
# local_app_data to have inferred type = RequirerAppModel
121118
local_app_data = self.foo.relations[0].local_app_data
122-
# so this will work although you have to type it manually
119+
# getitem notation will still work (for legacy compatibility),
120+
# however you will have to type it manually (with more modern python
121+
# versions you might be able to pass a TypedDict instance and get
122+
# those type annotations too).
123123
foo_value: int = local_app_data['foo']
124124

125125
# using dot notation:
126126
# the IDE will autocomplete `.foo` for you, and mypy will know that foo_value_dot: int
127127
foo_value_dot = local_app_data.foo
128-
# mypy will bash you here, because `.foo` is typed as an int, and 2.3 is a float...
128+
# mypy will smite you here, because `.foo` is typed as an int, and 2.3 is a float...
129129
local_app_data.foo = 2.3
130130

131131
# equivalent to adding an on_joined kwarg to the Endpoint:
@@ -134,36 +134,56 @@ class MyCharm(CharmBase):
134134
def _on_foo_changed(self, event):
135135
# we can check whether:
136136

137-
# local application data is valid:
138-
if self.foo.__local_app_data_valid:
137+
# local data (app and unit) is valid:
138+
if self.foo.local_valid:
139139
self.do_stuff()
140140

141-
# remote data is valid: (for all related apps, for all related units).
141+
# FYI there are methods for checking individual databag validity, but they are private
142+
# for now:
143+
# if self.foo._local_units_data_valid: ...
144+
145+
# remote data (app and unit) is valid: (for all related apps, for all related units).
142146
if self.foo.remote_valid:
143147
self.do_stuff()
144148

145-
# all data is valid: (all remote and local data).
149+
# all data is valid: (all remote and local databags).
146150
if self.foo.valid:
147151
self.do_stuff()
148152

149153
# we can also idiomatically read/write data
150154
# this charm implements the requirer side of foo, so we have to look at RequirerAppModel.
151155

152156
for local_app_data in self.foo.local_apps_data.values():
153-
local_app_data['foo'] = 42
157+
local_app_data.foo = 42
154158
# equivalent to:
155159
# local_app_data.foo = 42 # mypy will understand this!
156160

157161
# since we installed pydantic:
158162
try:
159-
local_app_data['foo'] = 42.3
163+
local_app_data.foo = 42.3
160164
except ValidationError:
161-
pass
165+
print('caught this one!')
166+
167+
# also we can
168+
assert databag_valid(local_app_data) is True
169+
170+
# or
171+
try:
172+
validate_databag(local_app_data)
173+
except ValidationError:
174+
print('caught this one too!')
162175

163176
def _on_foo_joined(self, event):
164-
# we can 'wrap' an event's relation idiomatically:
165-
foo_relation = self.foo.wrap(event.relation)
166-
assert foo_relation.remote_app_data.valid
177+
# if we are within the context of an event that Endpoint wraps,
178+
# we can grab the Endpoint's `current` relation
179+
self.foo.current.local_unit_data.foo = 43
180+
181+
def _on_config_changed(self):
182+
# in non-relation-event handlers, we cannot use `current` but we can
183+
# 'wrap' an existing ops.model.Relation object idiomatically:
184+
foo_relation = self.foo.wrap(self.model.relations['foo'][0])
185+
foo_relation.local_unit_data.foo = 42
186+
assert databag_valid(foo_relation.remote_app_data)
167187
```
168188

169189
# Publishing

__version__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
version = 0
2-
revision = 8
2+
revision = 9

endpoint_wrapper.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ def __setattr__(self, key, value):
576576
self[key] = value
577577

578578
def __repr__(self):
579-
validity = self.valid
579+
validity = databag_valid(self)
580580
valid_str = (
581581
"valid" if validity else ("invalid" if validity is False else "unfilled")
582582
)
@@ -836,7 +836,7 @@ def publish_defaults(self, event):
836836

837837
# todo: wrap events before emitting them forward
838838
def wrap(self, relation: "OpsRelation") -> Relation[_A, _B, _C, _D]:
839-
"""Get the Relation wrapper object from an ops Relation object."""
839+
"""Get the Relation wrapper object from an ops.model.Relation object."""
840840
return next(filter(lambda r: r.wraps(relation), self.relations))
841841

842842
@property

scripts/bump-and-publish.sh

100644100755
File mode changed.

0 commit comments

Comments
 (0)