Skip to content

Commit a54e15f

Browse files
committed
fix: update charm dependent libs
1 parent 3d3044e commit a54e15f

File tree

11 files changed

+1679
-1033
lines changed

11 files changed

+1679
-1033
lines changed

lib/charms/certificate_transfer_interface/v1/certificate_transfer.py

Lines changed: 144 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,14 @@ def _on_certificates_removed(self, event: CertificatesRemovedEvent):
124124

125125
# Increment this PATCH version before using `charmcraft publish-lib` or reset
126126
# to 0 if you are raising the major API version
127-
LIBPATCH = 12
127+
LIBPATCH = 13
128128

129129
logger = logging.getLogger(__name__)
130130

131131
PYDEPS = ["pydantic"]
132132

133+
IS_PYDANTIC_V1 = int(pydantic.version.VERSION.split(".")[0]) < 2
134+
133135

134136
class TLSCertificatesError(Exception):
135137
"""Base class for custom errors raised by this library."""
@@ -139,10 +141,13 @@ class DataValidationError(TLSCertificatesError):
139141
"""Raised when data validation fails."""
140142

141143

142-
if int(pydantic.version.VERSION.split(".")[0]) < 2:
144+
class DatabagModel(pydantic.BaseModel):
145+
"""Base databag model.
146+
147+
Supports both pydantic v1 and v2.
148+
"""
143149

144-
class DatabagModel(pydantic.BaseModel): # type: ignore
145-
"""Base databag model."""
150+
if IS_PYDANTIC_V1:
146151

147152
class Config:
148153
"""Pydantic config."""
@@ -155,122 +160,117 @@ class Config:
155160

156161
_NEST_UNDER = None
157162

158-
@classmethod
159-
def load(cls, databag: MutableMapping):
160-
"""Load this model from a Juju databag."""
161-
if cls._NEST_UNDER:
162-
return cls.parse_obj(json.loads(databag[cls._NEST_UNDER]))
163-
164-
try:
165-
data = {
166-
k: json.loads(v)
167-
for k, v in databag.items()
168-
# Don't attempt to parse model-external values
169-
if k in {f.alias for f in cls.__fields__.values()}
170-
}
171-
except json.JSONDecodeError as e:
172-
msg = f"invalid databag contents: expecting json. {databag}"
173-
logger.error(msg)
174-
raise DataValidationError(msg) from e
175-
176-
try:
177-
return cls.parse_raw(json.dumps(data)) # type: ignore
178-
except pydantic.ValidationError as e:
179-
msg = f"failed to validate databag: {databag}"
180-
logger.debug(msg, exc_info=True)
181-
raise DataValidationError(msg) from e
182-
183-
def dump(self, databag: Optional[MutableMapping] = None, clear: bool = True):
184-
"""Write the contents of this model to Juju databag.
185-
186-
:param databag: the databag to write the data to.
187-
:param clear: ensure the databag is cleared before writing it.
188-
"""
189-
if clear and databag:
190-
databag.clear()
191-
192-
if databag is None:
193-
databag = {}
194-
195-
if self._NEST_UNDER:
196-
databag[self._NEST_UNDER] = self.json(by_alias=True, exclude_defaults=False)
197-
return databag
198-
199-
dct = json.loads(self.json(by_alias=True, exclude_defaults=False))
200-
databag.update({k: json.dumps(v) for k, v in dct.items()})
163+
model_config = pydantic.ConfigDict(
164+
# tolerate additional keys in databag
165+
extra="ignore",
166+
# Allow instantiating this class by field name (instead of forcing alias).
167+
populate_by_name=True,
168+
# Custom config key: whether to nest the whole datastructure (as json)
169+
# under a field or spread it out at the toplevel.
170+
_NEST_UNDER=None,
171+
) # type: ignore
172+
"""Pydantic config."""
173+
174+
@classmethod
175+
def load(cls, databag: MutableMapping):
176+
"""Load this model from a Juju databag."""
177+
if IS_PYDANTIC_V1:
178+
return cls._load_v1(databag)
179+
nest_under = cls.model_config.get("_NEST_UNDER")
180+
if nest_under:
181+
return cls.model_validate(json.loads(databag[nest_under]))
182+
183+
try:
184+
data = {
185+
k: json.loads(v)
186+
for k, v in databag.items()
187+
# Don't attempt to parse model-external values
188+
if k in {(f.alias or n) for n, f in cls.model_fields.items()}
189+
}
190+
except json.JSONDecodeError as e:
191+
msg = f"invalid databag contents: expecting json. {databag}"
192+
logger.error(msg)
193+
raise DataValidationError(msg) from e
194+
195+
try:
196+
return cls.model_validate_json(json.dumps(data))
197+
except pydantic.ValidationError as e:
198+
msg = f"failed to validate databag: {databag}"
199+
logger.debug(msg, exc_info=True)
200+
raise DataValidationError(msg) from e
201+
202+
@classmethod
203+
def _load_v1(cls, databag: MutableMapping):
204+
"""Load implementation for pydantic v1."""
205+
if cls._NEST_UNDER:
206+
return cls.parse_obj(json.loads(databag[cls._NEST_UNDER]))
207+
208+
try:
209+
data = {
210+
k: json.loads(v)
211+
for k, v in databag.items()
212+
# Don't attempt to parse model-external values
213+
if k in {f.alias for f in cls.__fields__.values()}
214+
}
215+
except json.JSONDecodeError as e:
216+
msg = f"invalid databag contents: expecting json. {databag}"
217+
logger.error(msg)
218+
raise DataValidationError(msg) from e
219+
220+
try:
221+
return cls.parse_raw(json.dumps(data)) # type: ignore
222+
except pydantic.ValidationError as e:
223+
msg = f"failed to validate databag: {databag}"
224+
logger.debug(msg, exc_info=True)
225+
raise DataValidationError(msg) from e
226+
227+
def dump(self, databag: Optional[MutableMapping] = None, clear: bool = True):
228+
"""Write the contents of this model to Juju databag.
201229
230+
Args:
231+
databag: The databag to write to.
232+
clear: Whether to clear the databag before writing.
233+
234+
Returns:
235+
MutableMapping: The databag.
236+
"""
237+
if IS_PYDANTIC_V1:
238+
return self._dump_v1(databag, clear)
239+
if clear and databag:
240+
databag.clear()
241+
242+
if databag is None:
243+
databag = {}
244+
nest_under = self.model_config.get("_NEST_UNDER")
245+
if nest_under:
246+
databag[nest_under] = self.model_dump_json(
247+
by_alias=True,
248+
# skip keys whose values are default
249+
exclude_defaults=True,
250+
)
202251
return databag
203252

204-
else:
205-
206-
class DatabagModel(pydantic.BaseModel):
207-
"""Base databag model."""
208-
209-
model_config = pydantic.ConfigDict(
210-
# tolerate additional keys in databag
211-
extra="ignore",
212-
# Allow instantiating this class by field name (instead of forcing alias).
213-
populate_by_name=True,
214-
# Custom config key: whether to nest the whole datastructure (as json)
215-
# under a field or spread it out at the toplevel.
216-
_NEST_UNDER=None,
217-
) # type: ignore
218-
"""Pydantic config."""
219-
220-
@classmethod
221-
def load(cls, databag: MutableMapping):
222-
"""Load this model from a Juju databag."""
223-
nest_under = cls.model_config.get("_NEST_UNDER")
224-
if nest_under:
225-
return cls.model_validate(json.loads(databag[nest_under]))
226-
227-
try:
228-
data = {
229-
k: json.loads(v)
230-
for k, v in databag.items()
231-
# Don't attempt to parse model-external values
232-
if k in {(f.alias or n) for n, f in cls.model_fields.items()}
233-
}
234-
except json.JSONDecodeError as e:
235-
msg = f"invalid databag contents: expecting json. {databag}"
236-
logger.error(msg)
237-
raise DataValidationError(msg) from e
238-
239-
try:
240-
return cls.model_validate_json(json.dumps(data))
241-
except pydantic.ValidationError as e:
242-
msg = f"failed to validate databag: {databag}"
243-
logger.debug(msg, exc_info=True)
244-
raise DataValidationError(msg) from e
245-
246-
def dump(self, databag: Optional[MutableMapping] = None, clear: bool = True):
247-
"""Write the contents of this model to Juju databag.
248-
249-
Args:
250-
databag: The databag to write to.
251-
clear: Whether to clear the databag before writing.
252-
253-
Returns:
254-
MutableMapping: The databag.
255-
"""
256-
if clear and databag:
257-
databag.clear()
258-
259-
if databag is None:
260-
databag = {}
261-
nest_under = self.model_config.get("_NEST_UNDER")
262-
if nest_under:
263-
databag[nest_under] = self.model_dump_json(
264-
by_alias=True,
265-
# skip keys whose values are default
266-
exclude_defaults=True,
267-
)
268-
return databag
253+
dct = self.model_dump(mode="json", by_alias=True, exclude_defaults=False)
254+
databag.update({k: json.dumps(v) for k, v in dct.items()})
255+
return databag
256+
257+
def _dump_v1(self, databag: Optional[MutableMapping] = None, clear: bool = True):
258+
"""Dump implementation for pydantic v1."""
259+
if clear and databag:
260+
databag.clear()
269261

270-
dct = self.model_dump(mode="json", by_alias=True, exclude_defaults=False)
271-
databag.update({k: json.dumps(v) for k, v in dct.items()})
262+
if databag is None:
263+
databag = {}
264+
265+
if self._NEST_UNDER:
266+
databag[self._NEST_UNDER] = self.json(by_alias=True, exclude_defaults=False)
272267
return databag
273268

269+
dct = json.loads(self.json(by_alias=True, exclude_defaults=False))
270+
databag.update({k: json.dumps(v) for k, v in dct.items()})
271+
272+
return databag
273+
274274

275275
class ProviderApplicationData(DatabagModel):
276276
"""Provider App databag model."""
@@ -337,10 +337,16 @@ def add_certificates(self, certificates: Set[str], relation_id: Optional[int] =
337337
return
338338
relations = self._get_active_relations(relation_id)
339339
if not relations:
340-
logger.warning(
341-
"At least 1 matching relation ID not found with the relation name '%s'",
342-
self.relationship_name,
343-
)
340+
if relation_id is not None:
341+
logger.warning(
342+
"At least 1 matching relation ID not found with the relation name '%s'",
343+
self.relationship_name,
344+
)
345+
else:
346+
logger.debug(
347+
"No active relations found with the relation name '%s'",
348+
self.relationship_name,
349+
)
344350
return
345351

346352
for relation in relations:
@@ -364,10 +370,16 @@ def remove_all_certificates(self, relation_id: Optional[int] = None) -> None:
364370
return
365371
relations = self._get_active_relations(relation_id)
366372
if not relations:
367-
logger.warning(
368-
"At least 1 matching relation ID not found with the relation name '%s'",
369-
self.relationship_name,
370-
)
373+
if relation_id is not None:
374+
logger.warning(
375+
"At least 1 matching relation ID not found with the relation name '%s'",
376+
self.relationship_name,
377+
)
378+
else:
379+
logger.debug(
380+
"No active relations found with the relation name '%s'",
381+
self.relationship_name,
382+
)
371383
return
372384

373385
for relation in relations:
@@ -394,10 +406,16 @@ def remove_certificate(
394406
return
395407
relations = self._get_active_relations(relation_id)
396408
if not relations:
397-
logger.warning(
398-
"At least 1 matching relation ID not found with the relation name '%s'",
399-
self.relationship_name,
400-
)
409+
if relation_id is not None:
410+
logger.warning(
411+
"At least 1 matching relation ID not found with the relation name '%s'",
412+
self.relationship_name,
413+
)
414+
else:
415+
logger.debug(
416+
"No active relations found with the relation name '%s'",
417+
self.relationship_name,
418+
)
401419
return
402420

403421
for relation in relations:

0 commit comments

Comments
 (0)