@@ -306,7 +306,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent):
306306 RelationEvent ,
307307)
308308from ops .framework import EventSource , Object
309- from ops .model import Application , Relation , Unit
309+ from ops .model import Application , ModelError , Relation , Unit
310310
311311# The unique Charmhub library identifier, never change it
312312LIBID = "6c3e6b6680d64e9c89e611d1a15f65be"
@@ -316,7 +316,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent):
316316
317317# Increment this PATCH version before using `charmcraft publish-lib` or reset
318318# to 0 if you are raising the major API version
319- LIBPATCH = 15
319+ LIBPATCH = 17
320320
321321PYDEPS = ["ops>=2.0.0" ]
322322
@@ -365,11 +365,11 @@ def diff(event: RelationChangedEvent, bucket: Union[Unit, Application]) -> Diff:
365365 return Diff (added , changed , deleted )
366366
367367
368- # Base DataProvides and DataRequires
368+ # Base DataRelation
369369
370370
371- class DataProvides (Object , ABC ):
372- """Base provides-side of the data products relation ."""
371+ class DataRelation (Object , ABC ):
372+ """Base relation data mainpulation class ."""
373373
374374 def __init__ (self , charm : CharmBase , relation_name : str ) -> None :
375375 super ().__init__ (charm , relation_name )
@@ -379,23 +379,11 @@ def __init__(self, charm: CharmBase, relation_name: str) -> None:
379379 self .relation_name = relation_name
380380 self .framework .observe (
381381 charm .on [relation_name ].relation_changed ,
382- self ._on_relation_changed ,
382+ self ._on_relation_changed_event ,
383383 )
384384
385- def _diff (self , event : RelationChangedEvent ) -> Diff :
386- """Retrieves the diff of the data in the relation changed databag.
387-
388- Args:
389- event: relation changed event.
390-
391- Returns:
392- a Diff instance containing the added, deleted and changed
393- keys from the event relation databag.
394- """
395- return diff (event , self .local_app )
396-
397385 @abstractmethod
398- def _on_relation_changed (self , event : RelationChangedEvent ) -> None :
386+ def _on_relation_changed_event (self , event : RelationChangedEvent ) -> None :
399387 """Event emitted when the relation data has changed."""
400388 raise NotImplementedError
401389
@@ -404,10 +392,11 @@ def fetch_relation_data(self) -> dict:
404392
405393 This function can be used to retrieve data from a relation
406394 in the charm code when outside an event callback.
395+ Function cannot be used in `*-relation-broken` events and will raise an exception.
407396
408397 Returns:
409398 a dict of the values stored in the relation data bag
410- for all relation instances (indexed by the relation id ).
399+ for all relation instances (indexed by the relation ID ).
411400 """
412401 data = {}
413402 for relation in self .relations :
@@ -430,13 +419,49 @@ def _update_relation_data(self, relation_id: int, data: dict) -> None:
430419 that should be updated in the relation.
431420 """
432421 if self .local_unit .is_leader ():
433- if relation := self .charm .model .get_relation (self .relation_name , relation_id ):
422+ relation = self .charm .model .get_relation (self .relation_name , relation_id )
423+ if relation :
434424 relation .data [self .local_app ].update (data )
435425
426+ @staticmethod
427+ def _is_relation_active (relation : Relation ):
428+ """Whether the relation is active based on contained data."""
429+ try :
430+ _ = repr (relation .data )
431+ return True
432+ except (RuntimeError , ModelError ):
433+ return False
434+
436435 @property
437436 def relations (self ) -> List [Relation ]:
438437 """The list of Relation instances associated with this relation_name."""
439- return list (self .charm .model .relations [self .relation_name ])
438+ return [
439+ relation
440+ for relation in self .charm .model .relations [self .relation_name ]
441+ if self ._is_relation_active (relation )
442+ ]
443+
444+
445+ # Base DataProvides and DataRequires
446+
447+
448+ class DataProvides (DataRelation ):
449+ """Base provides-side of the data products relation."""
450+
451+ def __init__ (self , charm : CharmBase , relation_name : str ) -> None :
452+ super ().__init__ (charm , relation_name )
453+
454+ def _diff (self , event : RelationChangedEvent ) -> Diff :
455+ """Retrieves the diff of the data in the relation changed databag.
456+
457+ Args:
458+ event: relation changed event.
459+
460+ Returns:
461+ a Diff instance containing the added, deleted and changed
462+ keys from the event relation databag.
463+ """
464+ return diff (event , self .local_app )
440465
441466 def set_credentials (self , relation_id : int , username : str , password : str ) -> None :
442467 """Set credentials.
@@ -476,7 +501,7 @@ def set_tls_ca(self, relation_id: int, tls_ca: str) -> None:
476501 self ._update_relation_data (relation_id , {"tls-ca" : tls_ca })
477502
478503
479- class DataRequires (Object , ABC ):
504+ class DataRequires (DataRelation ):
480505 """Requires-side of the relation."""
481506
482507 def __init__ (
@@ -487,62 +512,16 @@ def __init__(
487512 ):
488513 """Manager of base client relations."""
489514 super ().__init__ (charm , relation_name )
490- self .charm = charm
491515 self .extra_user_roles = extra_user_roles
492- self .local_app = self .charm .model .app
493- self .local_unit = self .charm .unit
494- self .relation_name = relation_name
495516 self .framework .observe (
496517 self .charm .on [relation_name ].relation_created , self ._on_relation_created_event
497518 )
498- self .framework .observe (
499- self .charm .on [relation_name ].relation_changed , self ._on_relation_changed_event
500- )
501519
502520 @abstractmethod
503521 def _on_relation_created_event (self , event : RelationCreatedEvent ) -> None :
504522 """Event emitted when the relation is created."""
505523 raise NotImplementedError
506524
507- @abstractmethod
508- def _on_relation_changed_event (self , event : RelationChangedEvent ) -> None :
509- raise NotImplementedError
510-
511- def fetch_relation_data (self ) -> dict :
512- """Retrieves data from relation.
513-
514- This function can be used to retrieve data from a relation
515- in the charm code when outside an event callback.
516- Function cannot be used in `*-relation-broken` events and will raise an exception.
517-
518- Returns:
519- a dict of the values stored in the relation data bag
520- for all relation instances (indexed by the relation ID).
521- """
522- data = {}
523- for relation in self .relations :
524- data [relation .id ] = (
525- {key : value for key , value in relation .data [relation .app ].items () if key != "data" }
526- if relation .app
527- else {}
528- )
529- return data
530-
531- def _update_relation_data (self , relation_id : int , data : dict ) -> None :
532- """Updates a set of key-value pairs in the relation.
533-
534- This function writes in the application data bag, therefore,
535- only the leader unit can call it.
536-
537- Args:
538- relation_id: the identifier for a particular relation.
539- data: dict containing the key-value pairs
540- that should be updated in the relation.
541- """
542- if self .local_unit .is_leader ():
543- relation = self .charm .model .get_relation (self .relation_name , relation_id )
544- relation .data [self .local_app ].update (data )
545-
546525 def _diff (self , event : RelationChangedEvent ) -> Diff :
547526 """Retrieves the diff of the data in the relation changed databag.
548527
@@ -555,23 +534,6 @@ def _diff(self, event: RelationChangedEvent) -> Diff:
555534 """
556535 return diff (event , self .local_unit )
557536
558- @property
559- def relations (self ) -> List [Relation ]:
560- """The list of Relation instances associated with this relation_name."""
561- return [
562- relation
563- for relation in self .charm .model .relations [self .relation_name ]
564- if self ._is_relation_active (relation )
565- ]
566-
567- @staticmethod
568- def _is_relation_active (relation : Relation ):
569- try :
570- _ = repr (relation .data )
571- return True
572- except RuntimeError :
573- return False
574-
575537 @staticmethod
576538 def _is_resource_created_for_relation (relation : Relation ) -> bool :
577539 if not relation .app :
@@ -797,7 +759,7 @@ class DatabaseProvides(DataProvides):
797759 def __init__ (self , charm : CharmBase , relation_name : str ) -> None :
798760 super ().__init__ (charm , relation_name )
799761
800- def _on_relation_changed (self , event : RelationChangedEvent ) -> None :
762+ def _on_relation_changed_event (self , event : RelationChangedEvent ) -> None :
801763 """Event emitted when the relation has changed."""
802764 # Only the leader should handle this event.
803765 if not self .local_unit .is_leader ():
@@ -938,11 +900,8 @@ def _assign_relation_alias(self, relation_id: int) -> None:
938900
939901 # Return if an alias was already assigned to this relation
940902 # (like when there are more than one unit joining the relation).
941- if (
942- self .charm .model .get_relation (self .relation_name , relation_id )
943- .data [self .local_unit ]
944- .get ("alias" )
945- ):
903+ relation = self .charm .model .get_relation (self .relation_name , relation_id )
904+ if relation and relation .data [self .local_unit ].get ("alias" ):
946905 return
947906
948907 # Retrieve the available aliases (the ones that weren't assigned to any relation).
@@ -955,7 +914,8 @@ def _assign_relation_alias(self, relation_id: int) -> None:
955914
956915 # Set the alias in the unit relation databag of the specific relation.
957916 relation = self .charm .model .get_relation (self .relation_name , relation_id )
958- relation .data [self .local_unit ].update ({"alias" : available_aliases [0 ]})
917+ if relation :
918+ relation .data [self .local_unit ].update ({"alias" : available_aliases [0 ]})
959919
960920 def _emit_aliased_event (self , event : RelationChangedEvent , event_name : str ) -> None :
961921 """Emit an aliased event to a particular relation if it has an alias.
@@ -1197,7 +1157,7 @@ class KafkaProvides(DataProvides):
11971157 def __init__ (self , charm : CharmBase , relation_name : str ) -> None :
11981158 super ().__init__ (charm , relation_name )
11991159
1200- def _on_relation_changed (self , event : RelationChangedEvent ) -> None :
1160+ def _on_relation_changed_event (self , event : RelationChangedEvent ) -> None :
12011161 """Event emitted when the relation has changed."""
12021162 # Only the leader should handle this event.
12031163 if not self .local_unit .is_leader ():
@@ -1377,7 +1337,7 @@ class OpenSearchProvides(DataProvides):
13771337 def __init__ (self , charm : CharmBase , relation_name : str ) -> None :
13781338 super ().__init__ (charm , relation_name )
13791339
1380- def _on_relation_changed (self , event : RelationChangedEvent ) -> None :
1340+ def _on_relation_changed_event (self , event : RelationChangedEvent ) -> None :
13811341 """Event emitted when the relation has changed."""
13821342 # Only the leader should handle this event.
13831343 if not self .local_unit .is_leader ():
0 commit comments