def test_example_aggregate_event_classes(self): self.assertIn("Event", ExampleAggregateRoot.__dict__) self.assertIn("Created", ExampleAggregateRoot.__dict__) self.assertIn("Discarded", ExampleAggregateRoot.__dict__) self.assertIn("AttributeChanged", ExampleAggregateRoot.__dict__) self.assertEqual(ExampleAggregateRoot.Event.__name__, "Event") self.assertEqual(ExampleAggregateRoot.Event.__qualname__, "ExampleAggregateRoot.Event") topic = "eventsourcing.tests.core_tests.test_aggregate_root#ExampleAggregateRoot.Event" self.assertEqual(get_topic(ExampleAggregateRoot.Event), topic) self.assertEqual(resolve_topic(topic), ExampleAggregateRoot.Event) self.assertEqual(ExampleAggregateRoot.Created.__name__, "Created") self.assertEqual(ExampleAggregateRoot.Created.__qualname__, "ExampleAggregateRoot.Created") topic = "eventsourcing.tests.core_tests.test_aggregate_root#ExampleAggregateRoot.Created" self.assertEqual(get_topic(ExampleAggregateRoot.Created), topic) self.assertEqual(resolve_topic(topic), ExampleAggregateRoot.Created) self.assertTrue(issubclass(ExampleAggregateRoot.Created, ExampleAggregateRoot.Event)) self.assertEqual(ExampleAggregateRoot.Discarded.__name__, "Discarded") self.assertEqual(ExampleAggregateRoot.Discarded.__qualname__, "ExampleAggregateRoot.Discarded") topic = "eventsourcing.tests.core_tests.test_aggregate_root#ExampleAggregateRoot.Discarded" self.assertEqual(get_topic(ExampleAggregateRoot.Discarded), topic) self.assertEqual(resolve_topic(topic), ExampleAggregateRoot.Discarded) self.assertTrue(issubclass(ExampleAggregateRoot.Discarded, ExampleAggregateRoot.Event)) self.assertEqual(ExampleAggregateRoot.ExampleCreated.__name__, "ExampleCreated") self.assertEqual(ExampleAggregateRoot.ExampleCreated.__qualname__, "ExampleAggregateRoot.ExampleCreated") topic = "eventsourcing.tests.core_tests.test_aggregate_root#ExampleAggregateRoot.ExampleCreated" self.assertEqual(get_topic(ExampleAggregateRoot.ExampleCreated), topic) self.assertEqual(resolve_topic(topic), ExampleAggregateRoot.ExampleCreated) self.assertTrue(issubclass(ExampleAggregateRoot.ExampleCreated, ExampleAggregateRoot.Event))
def _decode_object(d): topic = d['__class__']['topic'] state = d['__class__']['state'] obj_class = resolve_topic(topic) obj = object.__new__(obj_class) obj.__dict__.update(state) return obj
def entity_from_snapshot(snapshot): """ Reconstructs domain entity from given snapshot. """ assert isinstance(snapshot, AbstractSnapshop), type(snapshot) if snapshot.state is not None: entity_class = resolve_topic(snapshot.topic) return reconstruct_object(entity_class, snapshot.state)
def decode_frozenset(d): set_data = d["__frozenset__"] if isinstance(set_data, dict): topic = set_data["topic"] state = set_data["state"] set_type = resolve_topic(topic) return set_type(state) else: return frozenset(set_data)
def __mutate__(self, obj: Optional[TDomainEntity]) -> Optional[TDomainEntity]: """ Constructs object from an entity class, which is obtained by resolving the originator topic, unless it is given as method argument ``entity_class``. :param entity_class: Class of domain entity to be constructed. """ entity_class: Type[TDomainEntity] = resolve_topic(self.originator_topic) return entity_class(**self.__entity_kwargs__)
def __mutate__(self, entity_class=None): if entity_class is None: entity_class = resolve_topic(self.originator_topic) with_data_integrity = getattr(entity_class, '__with_data_integrity__', True) if with_data_integrity: self.__check_hash__() obj = entity_class(**self.__entity_kwargs__) if with_data_integrity: obj.__head__ = self.__event_hash__ return obj
def _decode_object(d): topic = d['__class__']['topic'] state = d['__class__']['state'] obj_class = resolve_topic(topic) obj = object.__new__(obj_class) if hasattr(obj, '__dict__'): obj.__dict__.update(state) else: for k, v in state.items(): object.__setattr__(obj, k, v) return obj
def get_event_class_and_attrs(self, topic, state): # Resolve topic to event class. domain_event_class = resolve_topic(topic) # Decrypt state. if self.cipher: state = self.cipher.decrypt(state) # Deserialize data. event_attrs = json_loads(state, cls=self.json_decoder_class) return domain_event_class, event_attrs
def decode_object(d): topic = d["__class__"]["topic"] state = d["__class__"]["state"] obj_class = resolve_topic(topic) obj = object.__new__(obj_class) if hasattr(obj, "__dict__"): obj.__dict__.update(state) else: for k, v in state.items(): object.__setattr__(obj, k, v) return obj
def decode_tuple(d): topic = d["__tuple__"]["topic"] state = d["__tuple__"]["state"] tuple_type = resolve_topic(topic) if topic == "builtins#tuple": # For standard tuple objects. obj = tuple_type(state) else: # For NamedTuple objects. obj = tuple_type(*state) return obj
def __mutate__(self, entity_class=None): """ Constructs object from an entity class, which is obtained by resolving the originator topic, unless it is given as method argument ``entity_class``. :param entity_class: Class of domain entity to be constructed. """ if entity_class is None: entity_class = resolve_topic(self.originator_topic) return entity_class(**self.__entity_kwargs__)
def test_aggregate1_event_classes(self): self.assertIn("Event", Aggregate1.__dict__) self.assertIn("Created", Aggregate1.__dict__) self.assertIn("Discarded", Aggregate1.__dict__) self.assertIn("AttributeChanged", Aggregate1.__dict__) self.assertEqual(Aggregate1.Event.__name__, "Event") self.assertEqual(Aggregate1.Event.__qualname__, "Aggregate1.Event") topic = "eventsourcing.tests.core_tests.test_aggregate_root#Aggregate1.Event" self.assertEqual(get_topic(Aggregate1.Event), topic) self.assertEqual(resolve_topic(topic), Aggregate1.Event) self.assertEqual(Aggregate1.Created.__name__, "Created") self.assertEqual(Aggregate1.Created.__qualname__, "Aggregate1.Created") topic = "eventsourcing.tests.core_tests.test_aggregate_root#Aggregate1.Created" self.assertEqual(get_topic(Aggregate1.Created), topic) self.assertEqual(resolve_topic(topic), Aggregate1.Created) self.assertTrue(issubclass(Aggregate1.Created, Aggregate1.Event)) self.assertEqual(Aggregate1.Discarded.__name__, "Discarded") self.assertEqual(Aggregate1.Discarded.__qualname__, "Aggregate1.Discarded") topic = ( "eventsourcing.tests.core_tests.test_aggregate_root#Aggregate1" ".Discarded") self.assertEqual(get_topic(Aggregate1.Discarded), topic) self.assertEqual(resolve_topic(topic), Aggregate1.Discarded) self.assertTrue(issubclass(Aggregate1.Discarded, Aggregate1.Event)) self.assertEqual(Aggregate1.ExampleCreated.__name__, "ExampleCreated") self.assertEqual(Aggregate1.ExampleCreated.__qualname__, "Aggregate1.ExampleCreated") topic = ( "eventsourcing.tests.core_tests.test_aggregate_root#Aggregate1" ".ExampleCreated") self.assertEqual(get_topic(Aggregate1.ExampleCreated), topic) self.assertEqual(resolve_topic(topic), Aggregate1.ExampleCreated) self.assertTrue(issubclass(Aggregate1.ExampleCreated, Aggregate1.Event)) self.assertTrue( issubclass(Aggregate1.SomethingElseOccurred, Aggregate1.Event))
def decode_tuple(d): tuple_data = d["__tuple__"] if type(tuple_data) == dict: # For NamedTuple objects. topic = tuple_data["topic"] state = tuple_data["state"] tuple_type = resolve_topic(topic) obj = tuple_type(*state) else: # For standard tuple objects. obj = tuple(tuple_data) return obj
def decode_deque(d): deque_data = d["__deque__"] if type(deque_data) == dict: topic = deque_data["topic"] try: state = deque_data["state"] except KeyError: state = deque_data["values"] deque_type = resolve_topic(topic) return deque_type(state) else: return deque(deque_data)
def example_policy(process, repository, event): # Whenever an aggregate is created, then "move it on". if isinstance(event, ExampleAggregate.Created): # Get aggregate and move it on. aggregate = repository[event.originator_id] assert isinstance(aggregate, ExampleAggregate) aggregate.move_on() elif isinstance(event, Command.Created): command_class = resolve_topic(event.originator_topic) if command_class is CreateExample: return ExampleAggregate.__create__()
def from_topic_and_data(self, topic, data): # Resolve topic to event class. domain_event_class = resolve_topic(topic) # Decrypt data. if self.cipher: data = self.cipher.decrypt(data) # Deserialize data. event_attrs = json_loads(data, cls=self.json_decoder_class) # Reconstruct domain event object. return reconstruct_object(domain_event_class, event_attrs)
def test_topic_resolution_error(self): # Check topic resolution error is raised, if the module path is # broken, and if the class name is broken. resolve_topic("eventsourcing.domain.model.events#DomainEvent") with self.assertRaises(TopicResolutionError): resolve_topic("eventsourcing.domain.model.broken#DomainEvent") with self.assertRaises(TopicResolutionError): resolve_topic("eventsourcing.domain.model.events#Broken")
def example_policy(repository, event): # Whenever an aggregate is created, then "move it on". if isinstance(event, ExampleAggregate.Created): # Get aggregate and move it on. aggregate = repository[event.originator_id] assert isinstance(aggregate, ExampleAggregate) # Also create a second entity, allows test to check that # events from more than one entity are stored. second_id = uuid4() other_entity = AggregateRoot.__create__(originator_id=second_id) aggregate.move_on(second_id=second_id) return other_entity elif isinstance(event, Command.Created): command_class = resolve_topic(event.originator_topic) if command_class is CreateExample: return ExampleAggregate.__create__()
def example_policy(repository, event): if isinstance(event, ExampleAggregate.Created): # Create a second aggregate, allowing test to check that # events from more than one entity are stored. second_id = uuid4() second = AggregateRoot.__create__(originator_id=second_id) # Get first aggregate and move it on, allowing test to # check that the first aggregate was mutated by the policy. first = repository[event.originator_id] assert isinstance(first, ExampleAggregate) first.move_on(second_id=second_id) return second elif isinstance(event, Command.Created): command_class = resolve_topic(event.originator_topic) if command_class is CreateExample: return ExampleAggregate.__create__(event.example_id)
def get_event_class_and_attrs(self, topic: str, state: bytes) -> Tuple[Type[TEvent], Dict]: # Resolve topic to event class. domain_event_class: Type[TEvent] = resolve_topic(topic) # Decrypt and decompress state. if self.cipher: state = self.cipher.decrypt(state) # Decompress plaintext bytes. if self.compressor: state = self.compressor.decompress(state) # Decode unicode bytes. statestr = state.decode("utf8") # Deserialize JSON. event_attrs: Dict = self.json_loads(statestr) # Return instance class and attribute values. return domain_event_class, event_attrs
def __init__( self, application_topic, pipeline_id, infrastructure_topic, setup_table, address, upstreams, downstreams, push_prompt_interval, ): super(ProcessorServer, self).__init__() # Make getting notifications more efficient. notificationlog.USE_REGULAR_SECTIONS = False notificationlog.DEFAULT_SECTION_SIZE = 100 self.has_been_stopped = Event() signal(SIGINT, self.stop) self.application_class: Type[ProcessApplication] = resolve_topic( application_topic) self.pipeline_id = pipeline_id self.application_name = self.application_class.create_name() infrastructure_class: Type[ ApplicationWithConcreteInfrastructure] = resolve_topic( infrastructure_topic) self.application = self.application_class.mixin( infrastructure_class=infrastructure_class)( pipeline_id=self.pipeline_id, setup_table=setup_table) self.address = address self.json_encoder = ObjectJSONEncoder() self.json_decoder = ObjectJSONDecoder() self.upstreams = upstreams self.downstreams = downstreams self.prompt_events = {} self.push_prompt_interval = push_prompt_interval self.notification_log_view = NotificationLogView( self.application.notification_log, json_encoder=ObjectJSONEncoder(), ) for upstream_name in self.upstreams: self.prompt_events[upstream_name] = Event() # self.prompt_events[upstream_name].set() self.downstream_prompt_event = Event() subscribe(self._set_downstream_prompt_event, is_prompt_to_pull) self.serve() self.clients: Dict[str, ProcessorClient] = {} self.clients_lock = Lock() start_client_threads = [] remotes = {} remotes.update(self.upstreams) remotes.update(self.downstreams) for name, address in remotes.items(): thread = StartClient(self.clients, name, address) thread.setDaemon(True) thread.start() start_client_threads.append(thread) for thread in start_client_threads: thread.join() # logging.info("%s connected to %s" % (self.application_name, thread.name)) self.push_prompts_thread = Thread(target=self._push_prompts) self.push_prompts_thread.setDaemon(True) self.push_prompts_thread.start() # self.count_of_events = 0 self.pull_notifications_threads = {} self.unprocessed_domain_event_queue = Queue() for upstream_name, upstream_address in self.upstreams.items(): thread = PullNotifications( prompt_event=self.prompt_events[upstream_name], reader=NotificationLogReader( RemoteNotificationLog( client=self.clients[upstream_name], json_decoder=ObjectJSONDecoder(), section_size=self.application.notification_log. section_size, )), process_application=self.application, event_queue=self.unprocessed_domain_event_queue, upstream_name=upstream_name, has_been_stopped=self.has_been_stopped, ) thread.setDaemon(True) self.pull_notifications_threads[upstream_name] = thread self.process_events_thread = Thread(target=self._process_events) self.process_events_thread.setDaemon(True) self.process_events_thread.start() # Start the threads. for thread in self.pull_notifications_threads.values(): thread.start() # Wait for termination. self.wait_for_termination()
def decode_dict(d): topic = d["__dict__"]["topic"] state = d["__dict__"]["state"] dict_type = resolve_topic(topic) return dict_type(state)
def decode_deque(d): topic = d["__deque__"]["topic"] values = d["__deque__"]["values"] deque = resolve_topic(topic) return deque(values)
def get_event_class_and_attrs(self, topic: str, state: bytes) -> Tuple[Type[TEvent], Dict]: return resolve_topic(topic), state # type: ignore
def decode_enum(d): topic = d["__enum__"]["topic"] name = d["__enum__"]["name"] enum = resolve_topic(topic) return getattr(enum, name)
def decode_type(d): return resolve_topic(d["__type__"])
def __mutate__(self, entity_class=None): if entity_class is None: entity_class = resolve_topic(self.originator_topic) return entity_class(**self.__entity_kwargs__)
def __mutate__(self, obj: Optional[TEntity]) -> Optional[TEntity]: if self.state is not None: entity_class = resolve_topic(self.topic) return reconstruct_object(entity_class, self.state)