From 17c5899bf122d7835df4fa03ee953224b9da4f2a Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Tue, 30 Jan 2024 18:07:53 +0000 Subject: [PATCH 01/40] ENH: Allow setting of maximum number of parallel questions in `Child` --- octue/resources/child.py | 22 +++++++++++++++++++--- pyproject.toml | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/octue/resources/child.py b/octue/resources/child.py index d28c6308a..d5e0a11a0 100644 --- a/octue/resources/child.py +++ b/octue/resources/child.py @@ -9,6 +9,7 @@ logger = logging.getLogger(__name__) BACKEND_TO_SERVICE_MAPPING = {"GCPPubSubBackend": Service} +MAX_PARALLEL_QUESTIONS = 32 class Child: @@ -104,7 +105,14 @@ def ask( maximum_heartbeat_interval=maximum_heartbeat_interval, ) - def ask_multiple(self, *questions, raise_errors=True, max_retries=0, prevent_retries_when=None): + def ask_multiple( + self, + *questions, + raise_errors=True, + max_retries=0, + prevent_retries_when=None, + max_parallel_questions=MAX_PARALLEL_QUESTIONS, + ): """Ask the child multiple questions in parallel and wait for the answers. Each question should be provided as a dictionary of `Child.ask` keyword arguments. If `raise_errors` is `True`, an error is raised and no answers are returned if any of the individual questions raise an error; if it's `False`, answers are returned for all @@ -114,14 +122,21 @@ def ask_multiple(self, *questions, raise_errors=True, max_retries=0, prevent_ret :param bool raise_errors: if `True`, an error is raised and no answers are returned if any of the individual questions raise an error; if `False`, answers are returned for all successful questions while errors are returned unraised for any failed ones :param int max_retries: retry any questions that failed up to this number of times (note: this will have no effect unless `raise_errors=False`) :param list(type)|None prevent_retries_when: prevent retrying any questions that fail with an exception type in this list (note: this will have no effect unless `raise_errors=False`) - :raises Exception: if any question raises an error if `raise_errors` is `True` + :param int max_parallel_questions: the maximum number of questions that can be asked at once + :raise ValueError: if the maximum number of parallel questions is set too high + :raise Exception: if any question raises an error if `raise_errors` is `True` :return list: the answers or caught errors of the questions in the same order as asked """ + if max_parallel_questions > MAX_PARALLEL_QUESTIONS: + raise ValueError( + f"The maximum number of parallel questions cannot be above {MAX_PARALLEL_QUESTIONS}; received {max_parallel_questions}." + ) + prevent_retries_when = prevent_retries_when or [] # Answers will come out of order, so use a dictionary to store them against their questions' original index. answers = {} - max_workers = min(32, len(questions)) + max_workers = min(max_parallel_questions, len(questions)) logger.info("Asking %d questions.", len(questions)) with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: @@ -152,6 +167,7 @@ def ask_multiple(self, *questions, raise_errors=True, max_retries=0, prevent_ret if not failed_questions: break + logger.info("%d questions failed - retrying.", len(failed_questions)) retried_answers = self.ask_multiple(*failed_questions.values(), raise_errors=False) for question_index, answer in zip(failed_questions.keys(), retried_answers): diff --git a/pyproject.toml b/pyproject.toml index 783bb7c88..3d3105dda 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "octue" -version = "0.51.0" +version = "0.51.1" description = "A package providing template applications for data services, and a python SDK to the Octue API." readme = "README.md" authors = ["Marcus Lugg ", "Thomas Clark "] From 24d848efa64125d327ab3ae72248bc52e0d95f23 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Tue, 30 Jan 2024 18:25:30 +0000 Subject: [PATCH 02/40] ENH: Pull as many messages from subscription as possible at once --- octue/cloud/pub_sub/message_handler.py | 34 +++++++++++++-------- tests/cloud/pub_sub/test_message_handler.py | 26 ++++++++-------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index d4b2b4498..a0987ec22 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -27,6 +27,9 @@ logger = logging.getLogger(__name__) +MAX_SIMULTANEOUS_MESSAGES_PULL = 50 + + class OrderedMessageHandler: """A handler for Google Pub/Sub messages received via a pull subscription that ensures messages are handled in the order they were sent. @@ -134,7 +137,7 @@ def handle_messages(self, timeout=60, maximum_heartbeat_interval=300, skip_first while self._alive: pull_timeout = self._check_timeout_and_get_pull_timeout(timeout) - self._pull_and_enqueue_message(timeout=pull_timeout) + self._pull_and_enqueue_messages(timeout=pull_timeout) result = self._attempt_to_handle_queued_messages(skip_first_messages_after) if result is not None: @@ -186,9 +189,9 @@ def _check_timeout_and_get_pull_timeout(self, timeout): return timeout - total_run_time - def _pull_and_enqueue_message(self, timeout): - """Pull a message from the subscription and enqueue it in `self.waiting_messages`, raising a `TimeoutError` if - the timeout is exceeded before succeeding. + def _pull_and_enqueue_messages(self, timeout): + """Pull as many messages as are available from the subscription and enqueue them in `self.waiting_messages`, + raising a `TimeoutError` if the timeout is exceeded before succeeding. :param float|None timeout: how long to wait in seconds for the message before raising a `TimeoutError` :raise TimeoutError|concurrent.futures.TimeoutError: if the timeout is exceeded @@ -201,15 +204,13 @@ def _pull_and_enqueue_message(self, timeout): logger.debug("Pulling messages from Google Pub/Sub: attempt %d.", attempt) pull_response = self._subscriber.pull( - request={"subscription": self.subscription.path, "max_messages": 1}, + request={"subscription": self.subscription.path, "max_messages": MAX_SIMULTANEOUS_MESSAGES_PULL}, retry=retry.Retry(), ) - try: - answer = pull_response.received_messages[0] + if len(pull_response.received_messages) > 0: break - - except IndexError: + else: logger.debug("Google Pub/Sub pull response timed out early.") attempt += 1 @@ -220,10 +221,19 @@ def _pull_and_enqueue_message(self, timeout): f"No message received from topic {self.subscription.topic.path!r} after {timeout} seconds.", ) - self._subscriber.acknowledge(request={"subscription": self.subscription.path, "ack_ids": [answer.ack_id]}) - logger.debug("%r received a message related to question %r.", self.receiving_service, self.question_uuid) + self._subscriber.acknowledge( + request={ + "subscription": self.subscription.path, + "ack_ids": [message.ack_id for message in pull_response.received_messages], + } + ) - event, attributes = extract_event_and_attributes_from_pub_sub(answer.message) + for message in pull_response.received_messages: + self._extract_and_enqueue_event(message) + + def _extract_and_enqueue_event(self, message): + logger.debug("%r received a message related to question %r.", self.receiving_service, self.question_uuid) + event, attributes = extract_event_and_attributes_from_pub_sub(message.message) if not is_event_valid( event=event, diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index 11c158cf6..c9b5c99a7 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -38,7 +38,7 @@ def test_timeout(self): ) with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller( messages=[MockMessage(b"")], message_handler=message_handler, @@ -65,7 +65,7 @@ def test_in_order_messages_are_handled_in_order(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages() @@ -91,7 +91,7 @@ def test_out_of_order_messages_are_handled_in_order(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages() @@ -120,7 +120,7 @@ def test_out_of_order_messages_with_end_message_first_are_handled_in_order(self) ) with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller( messages=[ MockMessage.from_primitive({"kind": "finish-test", "order": 3}, attributes={"message_number": 3}), @@ -162,7 +162,7 @@ def test_no_timeout(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages(timeout=None) @@ -182,7 +182,7 @@ def test_delivery_acknowledgement(self): ) with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller( [ MockMessage.from_primitive( @@ -212,7 +212,7 @@ def test_error_raised_if_heartbeat_not_received_before_checked(self): receiving_service=receiving_service, ) - with patch("octue.cloud.pub_sub.message_handler.OrderedMessageHandler._pull_and_enqueue_message"): + with patch("octue.cloud.pub_sub.message_handler.OrderedMessageHandler._pull_and_enqueue_messages"): with self.assertRaises(TimeoutError) as error: message_handler.handle_messages(maximum_heartbeat_interval=0) @@ -245,7 +245,7 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte message_handler._last_heartbeat = datetime.datetime.now() with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller( messages=[ MockMessage.from_primitive( @@ -313,7 +313,7 @@ def test_handler_can_skip_first_n_messages_if_missed(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages(skip_first_messages_after=0) @@ -347,7 +347,7 @@ def test_later_missing_messages_cannot_be_skipped(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_message", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): with self.assertRaises(TimeoutError): @@ -365,7 +365,7 @@ def test_later_missing_messages_cannot_be_skipped(self): class TestPullAndEnqueueMessage(BaseTestCase): - def test_pull_and_enqueue_message(self): + def test_pull_and_enqueue_messages(self): """Test that pulling and enqueuing a message works.""" question_uuid = "4d31bb46-66c4-4e68-831f-e51e17e651ef" @@ -401,7 +401,7 @@ def test_pull_and_enqueue_message(self): ) ] - message_handler._pull_and_enqueue_message(timeout=10) + message_handler._pull_and_enqueue_messages(timeout=10) self.assertEqual(message_handler.waiting_messages, {0: mock_message}) self.assertEqual(message_handler._earliest_message_number_received, 0) @@ -430,6 +430,6 @@ def test_timeout_error_raised_if_result_message_not_received_in_time(self): SUBSCRIPTIONS[mock_subscription.name] = [] with self.assertRaises(TimeoutError): - message_handler._pull_and_enqueue_message(timeout=1e-6) + message_handler._pull_and_enqueue_messages(timeout=1e-6) self.assertEqual(message_handler._earliest_message_number_received, math.inf) From 8c896081c0cb9bfcab6d0dcdc79013814004d093 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 11:00:38 +0000 Subject: [PATCH 03/40] REF: Rename `OrderedMessageHandler` method --- octue/cloud/pub_sub/message_handler.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index a0987ec22..331736900 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -138,7 +138,7 @@ def handle_messages(self, timeout=60, maximum_heartbeat_interval=300, skip_first while self._alive: pull_timeout = self._check_timeout_and_get_pull_timeout(timeout) self._pull_and_enqueue_messages(timeout=pull_timeout) - result = self._attempt_to_handle_queued_messages(skip_first_messages_after) + result = self._attempt_to_handle_waiting_messages(skip_first_messages_after) if result is not None: return result @@ -253,9 +253,9 @@ def _extract_and_enqueue_event(self, message): self.waiting_messages[message_number] = event self._earliest_message_number_received = min(self._earliest_message_number_received, message_number) - def _attempt_to_handle_queued_messages(self, skip_first_messages_after=60): - """Attempt to handle messages in the pulled message queue. If these messages aren't consecutive with the last - handled message (i.e. if messages have been received out of order and the next in-order message hasn't been + def _attempt_to_handle_waiting_messages(self, skip_first_messages_after=60): + """Attempt to handle messages waiting in the pulled message queue. If these messages aren't consecutive to the + last handled message (i.e. if messages have been received out of order and the next in-order message hasn't been received yet), just return. After the given amount of time, if the first n messages haven't arrived but subsequent ones have, skip to the earliest received message and continue from there. From 78d3a20671830f70ca4ca5365a013e3baa7d86ef Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 11:14:29 +0000 Subject: [PATCH 04/40] ENH: Allow skipping of missing messages beyond the first n messages --- octue/cloud/pub_sub/message_handler.py | 31 ++++++++++---------- tests/cloud/pub_sub/test_message_handler.py | 32 ++++++++++----------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 331736900..9fc61c716 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -75,7 +75,7 @@ def __init__( self._alive = True self._start_time = None self._previous_message_number = -1 - self._earliest_message_number_received = math.inf + self._earliest_waiting_message_number = math.inf self._message_handlers = message_handlers or { "delivery_acknowledgement": self._handle_delivery_acknowledgement, @@ -137,7 +137,7 @@ def handle_messages(self, timeout=60, maximum_heartbeat_interval=300, skip_first while self._alive: pull_timeout = self._check_timeout_and_get_pull_timeout(timeout) - self._pull_and_enqueue_messages(timeout=pull_timeout) + self._pull_and_enqueue_available_messages(timeout=pull_timeout) result = self._attempt_to_handle_waiting_messages(skip_first_messages_after) if result is not None: @@ -189,8 +189,8 @@ def _check_timeout_and_get_pull_timeout(self, timeout): return timeout - total_run_time - def _pull_and_enqueue_messages(self, timeout): - """Pull as many messages as are available from the subscription and enqueue them in `self.waiting_messages`, + def _pull_and_enqueue_available_messages(self, timeout): + """Pull as many messages from the subscription as are available and enqueue them in `self.waiting_messages`, raising a `TimeoutError` if the timeout is exceeded before succeeding. :param float|None timeout: how long to wait in seconds for the message before raising a `TimeoutError` @@ -251,7 +251,7 @@ def _extract_and_enqueue_event(self, message): message_number = attributes["message_number"] self.waiting_messages[message_number] = event - self._earliest_message_number_received = min(self._earliest_message_number_received, message_number) + self._earliest_waiting_message_number = min(self.waiting_messages.keys()) def _attempt_to_handle_waiting_messages(self, skip_first_messages_after=60): """Attempt to handle messages waiting in the pulled message queue. If these messages aren't consecutive to the @@ -268,8 +268,8 @@ def _attempt_to_handle_waiting_messages(self, skip_first_messages_after=60): except KeyError: - if self.total_run_time > skip_first_messages_after and self._previous_message_number == -1: - message = self._get_and_start_from_earliest_received_message(skip_first_messages_after) + if self.total_run_time > skip_first_messages_after: + message = self._get_and_start_from_earliest_waiting_message(skip_first_messages_after) if not message: return @@ -282,28 +282,27 @@ def _attempt_to_handle_waiting_messages(self, skip_first_messages_after=60): if result is not None: return result - def _get_and_start_from_earliest_received_message(self, skip_first_messages_after): - """Get the earliest received message from the waiting message queue and set the message handler up to start from - it instead of the first message sent by the child. + def _get_and_start_from_earliest_waiting_message(self, skip_first_messages_after): + """Get the earliest waiting message and set the message handler up to continue from it. :param int|float skip_first_messages_after: the number of seconds after which to skip the first n messages if they haven't arrived but subsequent messages have :return dict|None: """ try: - message = self.waiting_messages.pop(self._earliest_message_number_received) + message = self.waiting_messages.pop(self._earliest_waiting_message_number) except KeyError: return - self._previous_message_number = self._earliest_message_number_received - 1 + # Let the message handler know it can handle the next earliest message. + self._previous_message_number = self._earliest_waiting_message_number - 1 logger.warning( - "%r: The first %d messages for question %r weren't received after %ds - skipping to the " - "earliest received message (message number %d).", + "%r: Some messages for question %r weren't received after %ds - skipping to the next earliest received " + "message (message number %d).", self.receiving_service, - self._earliest_message_number_received, self.question_uuid, skip_first_messages_after, - self._earliest_message_number_received, + self._earliest_waiting_message_number, ) return message diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index c9b5c99a7..7b72f0b42 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -38,7 +38,7 @@ def test_timeout(self): ) with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller( messages=[MockMessage(b"")], message_handler=message_handler, @@ -65,7 +65,7 @@ def test_in_order_messages_are_handled_in_order(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages() @@ -91,7 +91,7 @@ def test_out_of_order_messages_are_handled_in_order(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages() @@ -120,7 +120,7 @@ def test_out_of_order_messages_with_end_message_first_are_handled_in_order(self) ) with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller( messages=[ MockMessage.from_primitive({"kind": "finish-test", "order": 3}, attributes={"message_number": 3}), @@ -162,7 +162,7 @@ def test_no_timeout(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages(timeout=None) @@ -182,7 +182,7 @@ def test_delivery_acknowledgement(self): ) with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller( [ MockMessage.from_primitive( @@ -212,7 +212,7 @@ def test_error_raised_if_heartbeat_not_received_before_checked(self): receiving_service=receiving_service, ) - with patch("octue.cloud.pub_sub.message_handler.OrderedMessageHandler._pull_and_enqueue_messages"): + with patch("octue.cloud.pub_sub.message_handler.OrderedMessageHandler._pull_and_enqueue_available_messages"): with self.assertRaises(TimeoutError) as error: message_handler.handle_messages(maximum_heartbeat_interval=0) @@ -245,7 +245,7 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte message_handler._last_heartbeat = datetime.datetime.now() with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller( messages=[ MockMessage.from_primitive( @@ -303,7 +303,7 @@ def test_handler_can_skip_first_n_messages_if_missed(self): ) # Simulate the first two messages not being received. - message_handler._earliest_message_number_received = 2 + message_handler._earliest_waiting_message_number = 2 messages = [ MockMessage.from_primitive({"kind": "test", "order": 2}, attributes={"message_number": 2}), @@ -313,7 +313,7 @@ def test_handler_can_skip_first_n_messages_if_missed(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): result = message_handler.handle_messages(skip_first_messages_after=0) @@ -347,7 +347,7 @@ def test_later_missing_messages_cannot_be_skipped(self): ] with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_messages", + "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): with self.assertRaises(TimeoutError): @@ -365,7 +365,7 @@ def test_later_missing_messages_cannot_be_skipped(self): class TestPullAndEnqueueMessage(BaseTestCase): - def test_pull_and_enqueue_messages(self): + def test_pull_and_enqueue_available_messages(self): """Test that pulling and enqueuing a message works.""" question_uuid = "4d31bb46-66c4-4e68-831f-e51e17e651ef" @@ -401,9 +401,9 @@ def test_pull_and_enqueue_messages(self): ) ] - message_handler._pull_and_enqueue_messages(timeout=10) + message_handler._pull_and_enqueue_available_messages(timeout=10) self.assertEqual(message_handler.waiting_messages, {0: mock_message}) - self.assertEqual(message_handler._earliest_message_number_received, 0) + self.assertEqual(message_handler._earliest_waiting_message_number, 0) def test_timeout_error_raised_if_result_message_not_received_in_time(self): """Test that a timeout error is raised if a result message is not received in time.""" @@ -430,6 +430,6 @@ def test_timeout_error_raised_if_result_message_not_received_in_time(self): SUBSCRIPTIONS[mock_subscription.name] = [] with self.assertRaises(TimeoutError): - message_handler._pull_and_enqueue_messages(timeout=1e-6) + message_handler._pull_and_enqueue_available_messages(timeout=1e-6) - self.assertEqual(message_handler._earliest_message_number_received, math.inf) + self.assertEqual(message_handler._earliest_waiting_message_number, math.inf) From 7b4d0db9b7aac36a594a3f1c5dcdbce7c21a2a1d Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 11:45:49 +0000 Subject: [PATCH 05/40] ENH: Allow skipping of missing messages every n seconds --- octue/cloud/pub_sub/message_handler.py | 36 ++++++++++++++------- tests/cloud/pub_sub/test_message_handler.py | 6 ++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 9fc61c716..3e73a8a39 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -41,6 +41,7 @@ class OrderedMessageHandler: :param str service_name: an arbitrary name to refer to the service subscribed to by (used for labelling its remote log messages) :param dict|None message_handlers: a mapping of message type names to callables that handle each type of message. The handlers should not mutate the messages. :param dict|str schema: the JSON schema (or URI of one) to validate messages against + :param int|float skip_missing_messages_after: the number of seconds after which to skip any messages if they haven't arrived but subsequent messages have :return None: """ @@ -53,12 +54,15 @@ def __init__( service_name="REMOTE", message_handlers=None, schema=SERVICE_COMMUNICATION_SCHEMA, + skip_missing_messages_after=60, ): self.subscription = subscription self.receiving_service = receiving_service self.handle_monitor_message = handle_monitor_message self.record_messages = record_messages self.service_name = service_name + self.skip_missing_messages_after = skip_missing_messages_after + self._missing_message_detection_time = None if isinstance(schema, str): self.schema = {"$ref": schema} @@ -96,10 +100,17 @@ def total_run_time(self): :return float|None: the amount of time since `self.handle_messages` was called (in seconds) """ if self._start_time is None: - return + return None return time.perf_counter() - self._start_time + @property + def time_since_missing_message(self): + if self._missing_message_detection_time is None: + return None + + return time.perf_counter() - self._missing_message_detection_time + @property def _time_since_last_heartbeat(self): """Get the time period since the last heartbeat was received. @@ -111,13 +122,12 @@ def _time_since_last_heartbeat(self): return datetime.now() - self._last_heartbeat - def handle_messages(self, timeout=60, maximum_heartbeat_interval=300, skip_first_messages_after=60): + def handle_messages(self, timeout=60, maximum_heartbeat_interval=300): """Pull messages and handle them in the order they were sent until a result is returned by a message handler, then return that result. :param float|None timeout: how long to wait for an answer before raising a `TimeoutError` :param int|float maximum_heartbeat_interval: the maximum amount of time (in seconds) allowed between child heartbeats before an error is raised - :param int|float skip_first_messages_after: the number of seconds after which to skip the first n messages if they haven't arrived but subsequent messages have :raise TimeoutError: if the timeout is exceeded before receiving the final message :return dict: the first result returned by a message handler """ @@ -138,7 +148,7 @@ def handle_messages(self, timeout=60, maximum_heartbeat_interval=300, skip_first while self._alive: pull_timeout = self._check_timeout_and_get_pull_timeout(timeout) self._pull_and_enqueue_available_messages(timeout=pull_timeout) - result = self._attempt_to_handle_waiting_messages(skip_first_messages_after) + result = self._attempt_to_handle_waiting_messages() if result is not None: return result @@ -253,23 +263,28 @@ def _extract_and_enqueue_event(self, message): self.waiting_messages[message_number] = event self._earliest_waiting_message_number = min(self.waiting_messages.keys()) - def _attempt_to_handle_waiting_messages(self, skip_first_messages_after=60): + def _attempt_to_handle_waiting_messages(self): """Attempt to handle messages waiting in the pulled message queue. If these messages aren't consecutive to the last handled message (i.e. if messages have been received out of order and the next in-order message hasn't been received yet), just return. After the given amount of time, if the first n messages haven't arrived but subsequent ones have, skip to the earliest received message and continue from there. - :param int|float skip_first_messages_after: the number of seconds after which to skip the first n messages if they haven't arrived but subsequent messages have :return any|None: either a non-`None` result from a message handler or `None` if nothing was returned by the message handlers or if the next in-order message hasn't been received yet """ while self.waiting_messages: try: + # If the next consecutive message has been received: message = self.waiting_messages.pop(self._previous_message_number + 1) + # If the next consecutive message hasn't been received: except KeyError: + self._missing_message_detection_time = time.perf_counter() + + if self.time_since_missing_message > self.skip_missing_messages_after: + message = self._skip_to_earliest_waiting_message() - if self.total_run_time > skip_first_messages_after: - message = self._get_and_start_from_earliest_waiting_message(skip_first_messages_after) + # Declare there are no more missing messages. + self._missing_message_detection_time = None if not message: return @@ -282,10 +297,9 @@ def _attempt_to_handle_waiting_messages(self, skip_first_messages_after=60): if result is not None: return result - def _get_and_start_from_earliest_waiting_message(self, skip_first_messages_after): + def _skip_to_earliest_waiting_message(self): """Get the earliest waiting message and set the message handler up to continue from it. - :param int|float skip_first_messages_after: the number of seconds after which to skip the first n messages if they haven't arrived but subsequent messages have :return dict|None: """ try: @@ -301,7 +315,7 @@ def _get_and_start_from_earliest_waiting_message(self, skip_first_messages_after "message (message number %d).", self.receiving_service, self.question_uuid, - skip_first_messages_after, + self.skip_missing_messages_after, self._earliest_waiting_message_number, ) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index 7b72f0b42..e1724fe7b 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -300,6 +300,7 @@ def test_handler_can_skip_first_n_messages_if_missed(self): receiving_service=receiving_service, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, + skip_missing_messages_after=0, ) # Simulate the first two messages not being received. @@ -316,7 +317,7 @@ def test_handler_can_skip_first_n_messages_if_missed(self): "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): - result = message_handler.handle_messages(skip_first_messages_after=0) + result = message_handler.handle_messages() self.assertEqual(result, "This is the result.") self.assertEqual( @@ -337,6 +338,7 @@ def test_later_missing_messages_cannot_be_skipped(self): receiving_service=receiving_service, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, + skip_missing_messages_after=0, ) messages = [ @@ -351,7 +353,7 @@ def test_later_missing_messages_cannot_be_skipped(self): new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, ): with self.assertRaises(TimeoutError): - message_handler.handle_messages(timeout=0.5, skip_first_messages_after=0) + message_handler.handle_messages(timeout=0.5) # Check that only the first three messages were handled. self.assertEqual( From 2d0093875ca2425fac5c54670a260a970573fe4e Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 13:49:56 +0000 Subject: [PATCH 06/40] TST: Test skipping missing messages in middle of message stream --- tests/cloud/pub_sub/test_message_handler.py | 70 ++++++++++++++++----- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index e1724fe7b..c7c4d012d 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -19,10 +19,21 @@ from tests.base import BaseTestCase +QUESTION_UUID = "1c766d5e-4c6c-456a-b1af-17c7f453999d" + + mock_topic = MockTopic(name="my-org.my-service.1-0-0", project_name=TEST_PROJECT_NAME) -mock_subscription = MockSubscription(name="my-org.my-service.1-0-0", topic=mock_topic, project_name=TEST_PROJECT_NAME) + +mock_subscription = MockSubscription( + name=f"my-org.my-service.1-0-0.answers.{QUESTION_UUID}", + topic=mock_topic, + project_name=TEST_PROJECT_NAME, +) +mock_subscription.create() + receiving_service = MockService( - service_id="my-org/my-service:1.0.0", backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME) + service_id="my-org/my-service:1.0.0", + backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME), ) @@ -290,7 +301,15 @@ def test_total_run_time_is_none_if_handle_messages_has_not_been_called(self): self.assertIsNone(message_handler.total_run_time) - def test_handler_can_skip_first_n_messages_if_missed(self): + def test_time_since_missing_message_is_none_if_no_missing_messages(self): + message_handler = OrderedMessageHandler( + subscription=mock_subscription, + receiving_service=receiving_service, + ) + + self.assertIsNone(message_handler.time_since_missing_message) + + def test_missing_messages_at_start_can_be_skipped(self): """Test that the first n messages can be skipped if they aren't received after a given time period if subsequent messages have been received. """ @@ -330,8 +349,7 @@ def test_handler_can_skip_first_n_messages_if_missed(self): ], ) - def test_later_missing_messages_cannot_be_skipped(self): - """Test that missing messages that aren't in the first n messages cannot be skipped.""" + def test_missing_messages_in_middle_can_skipped(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -341,27 +359,47 @@ def test_later_missing_messages_cannot_be_skipped(self): skip_missing_messages_after=0, ) + parent = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + + # Send three consecutive messages. messages = [ - MockMessage.from_primitive({"kind": "test", "order": 0}, attributes={"message_number": 0}), - MockMessage.from_primitive({"kind": "test", "order": 1}, attributes={"message_number": 1}), - MockMessage.from_primitive({"kind": "test", "order": 2}, attributes={"message_number": 2}), - MockMessage.from_primitive({"kind": "finish-test", "order": 5}, attributes={"message_number": 5}), + { + "event": {"kind": "test", "order": 0}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 1}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 2}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, ] - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, - ): - with self.assertRaises(TimeoutError): - message_handler.handle_messages(timeout=0.5) + for message in messages: + parent._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + # Simulate missing messages. + mock_topic.messages_published = 5 + + # Send a final message. + parent._send_message( + message={"kind": "finish-test", "order": 5}, + attributes={"message_number": 5, "question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + topic=mock_topic, + ) + + message_handler.handle_messages() - # Check that only the first three messages were handled. + # Check that only all the non-missing messages were handled. self.assertEqual( message_handler.handled_messages, [ {"kind": "test", "order": 0}, {"kind": "test", "order": 1}, {"kind": "test", "order": 2}, + {"kind": "finish-test", "order": 5}, ], ) From fd6a8f8c0b14a5ce53c1248b7d2d19f76e3df7b4 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 13:59:11 +0000 Subject: [PATCH 07/40] TST: Test other missing message scenarios --- tests/cloud/pub_sub/test_message_handler.py | 118 +++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index c7c4d012d..c0575e4f8 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -350,6 +350,7 @@ def test_missing_messages_at_start_can_be_skipped(self): ) def test_missing_messages_in_middle_can_skipped(self): + """Test that missing messages in the middle of the event stream can be skipped.""" with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -386,13 +387,13 @@ def test_missing_messages_in_middle_can_skipped(self): # Send a final message. parent._send_message( message={"kind": "finish-test", "order": 5}, - attributes={"message_number": 5, "question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + attributes={"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, topic=mock_topic, ) message_handler.handle_messages() - # Check that only all the non-missing messages were handled. + # Check that all the non-missing messages were handled. self.assertEqual( message_handler.handled_messages, [ @@ -403,6 +404,119 @@ def test_missing_messages_in_middle_can_skipped(self): ], ) + def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): + """Test that multiple blocks of missing messages in the middle of the event stream can be skipped.""" + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): + message_handler = OrderedMessageHandler( + subscription=mock_subscription, + receiving_service=receiving_service, + message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, + schema={}, + skip_missing_messages_after=0, + ) + + parent = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + + # Send three consecutive messages. + messages = [ + { + "event": {"kind": "test", "order": 0}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 1}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 2}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + ] + + for message in messages: + parent._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + # Simulate missing messages. + mock_topic.messages_published = 5 + + # Send another message. + parent._send_message( + message={"kind": "test", "order": 5}, + attributes={"message_number": 5, "question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + topic=mock_topic, + ) + + # Simulate more missing messages. + mock_topic.messages_published = 20 + + # Send more consecutive messages. + messages = [ + { + "event": {"kind": "test", "order": 20}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 21}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 22}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "finish-test", "order": 23}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + ] + + for message in messages: + parent._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + message_handler.handle_messages() + + # Check that all the non-missing messages were handled. + self.assertEqual( + message_handler.handled_messages, + [ + {"kind": "test", "order": 0}, + {"kind": "test", "order": 1}, + {"kind": "test", "order": 2}, + {"kind": "test", "order": 5}, + {"kind": "test", "order": 20}, + {"kind": "test", "order": 21}, + {"kind": "test", "order": 22}, + {"kind": "finish-test", "order": 23}, + ], + ) + + def test_all_messages_missing_apart_from_result(self): + """Test that the result message is still handled if all other messages are missing.""" + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): + message_handler = OrderedMessageHandler( + subscription=mock_subscription, + receiving_service=receiving_service, + message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, + schema={}, + skip_missing_messages_after=0, + ) + + parent = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + + # Simulate missing messages. + mock_topic.messages_published = 1000 + + # Send the result message. + parent._send_message( + message={"kind": "finish-test", "order": 1000}, + attributes={"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + topic=mock_topic, + ) + + message_handler.handle_messages() + + # Check that the result message was handled. + self.assertEqual(message_handler.handled_messages, [{"kind": "finish-test", "order": 1000}]) + class TestPullAndEnqueueMessage(BaseTestCase): def test_pull_and_enqueue_available_messages(self): From 99408e53a714145c8b0e9ded4f447a24afb6038f Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 14:05:24 +0000 Subject: [PATCH 08/40] REF: Factor out multiple checks of package version in message handler --- octue/cloud/pub_sub/message_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 3e73a8a39..c70e5fc26 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -28,6 +28,7 @@ MAX_SIMULTANEOUS_MESSAGES_PULL = 50 +PARENT_SDK_VERSION = importlib.metadata.version("octue") class OrderedMessageHandler: @@ -249,7 +250,7 @@ def _extract_and_enqueue_event(self, message): event=event, attributes=attributes, receiving_service=self.receiving_service, - parent_sdk_version=importlib.metadata.version("octue"), + parent_sdk_version=PARENT_SDK_VERSION, child_sdk_version=attributes.get("version"), schema=self.schema, ): From abff70d573896ba5f9c425dc841d75dbc4bf6e3a Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 14:12:31 +0000 Subject: [PATCH 09/40] TST: Use correct names for child and parent in message handler tests --- tests/cloud/pub_sub/test_message_handler.py | 59 ++++++++++----------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index c0575e4f8..aff117dac 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -31,10 +31,7 @@ ) mock_subscription.create() -receiving_service = MockService( - service_id="my-org/my-service:1.0.0", - backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME), -) +parent = MockService(service_id="my-org/my-service:1.0.0", backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) class TestOrderedMessageHandler(BaseTestCase): @@ -43,7 +40,7 @@ def test_timeout(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: message}, schema={}, ) @@ -63,7 +60,7 @@ def test_in_order_messages_are_handled_in_order(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, ) @@ -89,7 +86,7 @@ def test_out_of_order_messages_are_handled_in_order(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, ) @@ -125,7 +122,7 @@ def test_out_of_order_messages_with_end_message_first_are_handled_in_order(self) with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, ) @@ -161,7 +158,7 @@ def test_no_timeout(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, ) @@ -189,7 +186,7 @@ def test_delivery_acknowledgement(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, ) with patch( @@ -220,7 +217,7 @@ def test_error_raised_if_heartbeat_not_received_before_checked(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, ) with patch("octue.cloud.pub_sub.message_handler.OrderedMessageHandler._pull_and_enqueue_available_messages"): @@ -235,7 +232,7 @@ def test_error_raised_if_heartbeats_stop_being_received(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, ) message_handler._last_heartbeat = datetime.datetime.now() - datetime.timedelta(seconds=30) @@ -250,7 +247,7 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, ) message_handler._last_heartbeat = datetime.datetime.now() @@ -285,7 +282,7 @@ def test_time_since_last_heartbeat_is_none_if_no_heartbeat_received_yet(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, ) self.assertIsNone(message_handler._time_since_last_heartbeat) @@ -296,7 +293,7 @@ def test_total_run_time_is_none_if_handle_messages_has_not_been_called(self): """ message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, ) self.assertIsNone(message_handler.total_run_time) @@ -304,7 +301,7 @@ def test_total_run_time_is_none_if_handle_messages_has_not_been_called(self): def test_time_since_missing_message_is_none_if_no_missing_messages(self): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, ) self.assertIsNone(message_handler.time_since_missing_message) @@ -316,7 +313,7 @@ def test_missing_messages_at_start_can_be_skipped(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, skip_missing_messages_after=0, @@ -354,13 +351,13 @@ def test_missing_messages_in_middle_can_skipped(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, skip_missing_messages_after=0, ) - parent = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) # Send three consecutive messages. messages = [ @@ -379,13 +376,13 @@ def test_missing_messages_in_middle_can_skipped(self): ] for message in messages: - parent._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) # Simulate missing messages. mock_topic.messages_published = 5 # Send a final message. - parent._send_message( + child._send_message( message={"kind": "finish-test", "order": 5}, attributes={"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, topic=mock_topic, @@ -409,13 +406,13 @@ def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, skip_missing_messages_after=0, ) - parent = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) # Send three consecutive messages. messages = [ @@ -434,13 +431,13 @@ def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): ] for message in messages: - parent._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) # Simulate missing messages. mock_topic.messages_published = 5 # Send another message. - parent._send_message( + child._send_message( message={"kind": "test", "order": 5}, attributes={"message_number": 5, "question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, topic=mock_topic, @@ -470,7 +467,7 @@ def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): ] for message in messages: - parent._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) message_handler.handle_messages() @@ -494,19 +491,19 @@ def test_all_messages_missing_apart_from_result(self): with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, skip_missing_messages_after=0, ) - parent = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) # Simulate missing messages. mock_topic.messages_published = 1000 # Send the result message. - parent._send_message( + child._send_message( message={"kind": "finish-test", "order": 1000}, attributes={"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, topic=mock_topic, @@ -532,7 +529,7 @@ def test_pull_and_enqueue_available_messages(self): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, schema={}, ) @@ -572,7 +569,7 @@ def test_timeout_error_raised_if_result_message_not_received_in_time(self): message_handler = OrderedMessageHandler( subscription=mock_subscription, - receiving_service=receiving_service, + receiving_service=parent, message_handlers={"test": lambda message: None, "finish-test": lambda message: "This is the result."}, ) From a84a360b437c24c148ca9d3382a33bb2f23da601 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 14:54:35 +0000 Subject: [PATCH 10/40] TST: Stop mocking `_pull_and_enqueue_available_messages` method --- octue/cloud/emulators/_pub_sub.py | 31 --- tests/cloud/pub_sub/test_message_handler.py | 270 +++++++++++--------- 2 files changed, 150 insertions(+), 151 deletions(-) diff --git a/octue/cloud/emulators/_pub_sub.py b/octue/cloud/emulators/_pub_sub.py index 2ae70833a..be9331164 100644 --- a/octue/cloud/emulators/_pub_sub.py +++ b/octue/cloud/emulators/_pub_sub.py @@ -388,37 +388,6 @@ def ask( return response_subscription, question_uuid -class MockMessagePuller: - """A mock message puller that enqueues messages in the message handler in the order they're provided on - initialisation. This is meant for patching - `octue.cloud.pub_sub.message_handler.OrderedMessageHandler._pull_and_enqueue_message` in tests. - - :param iter(octue.cloud.pub_sub.emulators._pub_sub.MockMessage) messages: - :param octue.cloud.pub_sub.message_handler.OrderedMessageHandler message_handler: - :return None: - """ - - def __init__(self, messages, message_handler): - self.messages = messages - self.message_handler = message_handler - self.current_message = 0 - - def pull(self, timeout): - """Get the next message from the messages given at instantiation and enqueue it for handling in the message - handler. - - :return None: - """ - try: - message = self.messages[self.current_message] - except IndexError: - return - - message_number = int(message.attributes["message_number"]) - self.message_handler.waiting_messages[message_number] = json.loads(message.data.decode()) - self.current_message += 1 - - class MockAnalysis: """A mock Analysis object with just the output strands. diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index aff117dac..ec19319d0 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -1,12 +1,10 @@ import datetime -import json import math from unittest.mock import patch from octue.cloud.emulators._pub_sub import ( SUBSCRIPTIONS, MockMessage, - MockMessagePuller, MockService, MockSubscriber, MockSubscription, @@ -45,15 +43,8 @@ def test_timeout(self): schema={}, ) - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller( - messages=[MockMessage(b"")], - message_handler=message_handler, - ).pull, - ): - with self.assertRaises(TimeoutError): - message_handler.handle_messages(timeout=0) + with self.assertRaises(TimeoutError): + message_handler.handle_messages(timeout=0) def test_in_order_messages_are_handled_in_order(self): """Test that messages received in order are handled in order.""" @@ -65,21 +56,25 @@ def test_in_order_messages_are_handled_in_order(self): schema={}, ) + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + messages = [ - MockMessage.from_primitive({"kind": "test"}, attributes={"message_number": 0}), - MockMessage.from_primitive({"kind": "test"}, attributes={"message_number": 1}), - MockMessage.from_primitive({"kind": "test"}, attributes={"message_number": 2}), - MockMessage.from_primitive({"kind": "finish-test"}, attributes={"message_number": 3}), + {"event": {"kind": "test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, + {"event": {"kind": "test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, + {"event": {"kind": "test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, + {"event": {"kind": "finish-test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, ] - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, - ): - result = message_handler.handle_messages() + for message in messages: + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + result = message_handler.handle_messages() self.assertEqual(result, "This is the result.") - self.assertEqual(message_handler.handled_messages, [json.loads(message.data.decode()) for message in messages]) + + self.assertEqual( + message_handler.handled_messages, + [{"kind": "test"}, {"kind": "test"}, {"kind": "test"}, {"kind": "finish-test"}], + ) def test_out_of_order_messages_are_handled_in_order(self): """Test that messages received out of order are handled in order.""" @@ -91,20 +86,35 @@ def test_out_of_order_messages_are_handled_in_order(self): schema={}, ) + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + messages = [ - MockMessage.from_primitive({"kind": "test", "order": 1}, attributes={"message_number": 1}), - MockMessage.from_primitive({"kind": "test", "order": 2}, attributes={"message_number": 2}), - MockMessage.from_primitive({"kind": "test", "order": 0}, attributes={"message_number": 0}), - MockMessage.from_primitive({"kind": "finish-test", "order": 3}, attributes={"message_number": 3}), + { + "event": {"kind": "test", "order": 1}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 2}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 0}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "finish-test", "order": 3}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, ] - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, - ): - result = message_handler.handle_messages() + for message in messages: + mock_topic.messages_published = message["event"]["order"] + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + result = message_handler.handle_messages() self.assertEqual(result, "This is the result.") + self.assertEqual( message_handler.handled_messages, [ @@ -127,19 +137,32 @@ def test_out_of_order_messages_with_end_message_first_are_handled_in_order(self) schema={}, ) - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller( - messages=[ - MockMessage.from_primitive({"kind": "finish-test", "order": 3}, attributes={"message_number": 3}), - MockMessage.from_primitive({"kind": "test", "order": 1}, attributes={"message_number": 1}), - MockMessage.from_primitive({"kind": "test", "order": 2}, attributes={"message_number": 2}), - MockMessage.from_primitive({"kind": "test", "order": 0}, attributes={"message_number": 0}), - ], - message_handler=message_handler, - ).pull, - ): - result = message_handler.handle_messages() + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + + messages = [ + { + "event": {"kind": "finish-test", "order": 3}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 1}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 2}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 0}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + ] + + for message in messages: + mock_topic.messages_published = message["event"]["order"] + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + result = message_handler.handle_messages() self.assertEqual(result, "This is the result.") @@ -163,17 +186,27 @@ def test_no_timeout(self): schema={}, ) + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + messages = [ - MockMessage.from_primitive({"kind": "test", "order": 0}, attributes={"message_number": 0}), - MockMessage.from_primitive({"kind": "test", "order": 1}, attributes={"message_number": 1}), - MockMessage.from_primitive({"kind": "finish-test", "order": 2}, attributes={"message_number": 2}), + { + "event": {"kind": "test", "order": 0}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 1}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "finish-test", "order": 2}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, ] - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, - ): - result = message_handler.handle_messages(timeout=None) + for message in messages: + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + result = message_handler.handle_messages(timeout=None) self.assertEqual(result, "This is the result.") self.assertEqual( @@ -189,40 +222,32 @@ def test_delivery_acknowledgement(self): receiving_service=parent, ) - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller( - [ - MockMessage.from_primitive( - { - "kind": "delivery_acknowledgement", - "datetime": "2021-11-17 17:33:59.717428", - }, - attributes={"message_number": 0}, - ), - MockMessage.from_primitive( - {"kind": "result", "output_values": None, "output_manifest": None}, - attributes={"message_number": 1}, - ), - ], - message_handler=message_handler, - ).pull, - ): - result = message_handler.handle_messages() + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + messages = [ + { + "event": {"kind": "delivery_acknowledgement", "datetime": datetime.datetime.utcnow().isoformat()}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "result"}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + ] + + for message in messages: + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + result = message_handler.handle_messages() self.assertEqual(result, {"output_values": None, "output_manifest": None}) def test_error_raised_if_heartbeat_not_received_before_checked(self): """Test that an error is raised if a heartbeat isn't received before a heartbeat is first checked for.""" with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): - message_handler = OrderedMessageHandler( - subscription=mock_subscription, - receiving_service=parent, - ) + message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) - with patch("octue.cloud.pub_sub.message_handler.OrderedMessageHandler._pull_and_enqueue_available_messages"): - with self.assertRaises(TimeoutError) as error: - message_handler.handle_messages(maximum_heartbeat_interval=0) + with self.assertRaises(TimeoutError) as error: + message_handler.handle_messages(maximum_heartbeat_interval=0) # Check that the timeout is due to a heartbeat not being received. self.assertIn("heartbeat", error.exception.args[0]) @@ -252,30 +277,30 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte message_handler._last_heartbeat = datetime.datetime.now() + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + + messages = [ + { + "event": { + "kind": "delivery_acknowledgement", + "datetime": datetime.datetime.utcnow().isoformat(), + }, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "result"}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + ] + + for message in messages: + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller( - messages=[ - MockMessage.from_primitive( - { - "kind": "delivery_acknowledgement", - "datetime": "2021-11-17 17:33:59.717428", - }, - attributes={"message_number": 0}, - ), - MockMessage.from_primitive( - {"kind": "result", "output_values": None, "output_manifest": None}, - attributes={"message_number": 1}, - ), - ], - message_handler=message_handler, - ).pull, + "octue.cloud.pub_sub.message_handler.OrderedMessageHandler._time_since_last_heartbeat", + datetime.timedelta(seconds=0), ): - with patch( - "octue.cloud.pub_sub.message_handler.OrderedMessageHandler._time_since_last_heartbeat", - datetime.timedelta(seconds=0), - ): - message_handler.handle_messages(maximum_heartbeat_interval=0) + message_handler.handle_messages(maximum_heartbeat_interval=0) def test_time_since_last_heartbeat_is_none_if_no_heartbeat_received_yet(self): """Test that the time since the last heartbeat is `None` if no heartbeat has been received yet.""" @@ -291,19 +316,11 @@ def test_total_run_time_is_none_if_handle_messages_has_not_been_called(self): """Test that the total run time for the message handler is `None` if the `handle_messages` method has not been called. """ - message_handler = OrderedMessageHandler( - subscription=mock_subscription, - receiving_service=parent, - ) - + message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) self.assertIsNone(message_handler.total_run_time) def test_time_since_missing_message_is_none_if_no_missing_messages(self): - message_handler = OrderedMessageHandler( - subscription=mock_subscription, - receiving_service=parent, - ) - + message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) self.assertIsNone(message_handler.time_since_missing_message) def test_missing_messages_at_start_can_be_skipped(self): @@ -320,20 +337,33 @@ def test_missing_messages_at_start_can_be_skipped(self): ) # Simulate the first two messages not being received. - message_handler._earliest_waiting_message_number = 2 + mock_topic.messages_published = 2 + + child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) messages = [ - MockMessage.from_primitive({"kind": "test", "order": 2}, attributes={"message_number": 2}), - MockMessage.from_primitive({"kind": "test", "order": 3}, attributes={"message_number": 3}), - MockMessage.from_primitive({"kind": "test", "order": 4}, attributes={"message_number": 4}), - MockMessage.from_primitive({"kind": "finish-test", "order": 5}, attributes={"message_number": 5}), + { + "event": {"kind": "test", "order": 2}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 3}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "test", "order": 4}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, + { + "event": {"kind": "finish-test", "order": 5}, + "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + }, ] - with patch( - "octue.cloud.pub_sub.service.OrderedMessageHandler._pull_and_enqueue_available_messages", - new=MockMessagePuller(messages=messages, message_handler=message_handler).pull, - ): - result = message_handler.handle_messages() + for message in messages: + child._send_message(message=message["event"], attributes=message["attributes"], topic=mock_topic) + + result = message_handler.handle_messages() self.assertEqual(result, "This is the result.") self.assertEqual( From bf993378dcf7a56b7a48ce2a513c25ec5ed3c9d7 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 15:12:06 +0000 Subject: [PATCH 11/40] FIX: Only start missing messages timer if it isn't already running --- octue/cloud/pub_sub/message_handler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index c70e5fc26..98234663d 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -279,7 +279,9 @@ def _attempt_to_handle_waiting_messages(self): # If the next consecutive message hasn't been received: except KeyError: - self._missing_message_detection_time = time.perf_counter() + # Start the missing message timer if it isn't already running. + if self._missing_message_detection_time is None: + self._missing_message_detection_time = time.perf_counter() if self.time_since_missing_message > self.skip_missing_messages_after: message = self._skip_to_earliest_waiting_message() From 96a266ffcc44fc1f12fb36f0968fe41caede9dbf Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 15:21:59 +0000 Subject: [PATCH 12/40] TST: Create new topic for each message handler test --- tests/cloud/pub_sub/test_message_handler.py | 131 +++++++++++++------- 1 file changed, 84 insertions(+), 47 deletions(-) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index ec19319d0..af4f5f3d0 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -1,5 +1,6 @@ import datetime import math +import uuid from unittest.mock import patch from octue.cloud.emulators._pub_sub import ( @@ -17,24 +18,32 @@ from tests.base import BaseTestCase -QUESTION_UUID = "1c766d5e-4c6c-456a-b1af-17c7f453999d" +parent = MockService(service_id="my-org/my-service:1.0.0", backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) -mock_topic = MockTopic(name="my-org.my-service.1-0-0", project_name=TEST_PROJECT_NAME) +def create_mock_topic_and_subscription(): + """Create a question UUID, mock topic, and mock subscription. -mock_subscription = MockSubscription( - name=f"my-org.my-service.1-0-0.answers.{QUESTION_UUID}", - topic=mock_topic, - project_name=TEST_PROJECT_NAME, -) -mock_subscription.create() + :return (str, octue.cloud.emulators._pub_sub.MockTopic, octue.cloud.emulators._pub_sub.MockSubscription): question UUID, topic, and subscription + """ + question_uuid = str(uuid.uuid4()) + topic = MockTopic(name="my-org.my-service.1-0-0", project_name=TEST_PROJECT_NAME) -parent = MockService(service_id="my-org/my-service:1.0.0", backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) + subscription = MockSubscription( + name=f"my-org.my-service.1-0-0.answers.{question_uuid}", + topic=topic, + project_name=TEST_PROJECT_NAME, + ) + + subscription.create() + return question_uuid, topic, subscription class TestOrderedMessageHandler(BaseTestCase): def test_timeout(self): """Test that a TimeoutError is raised if message handling takes longer than the given timeout.""" + question_uuid, _, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -48,6 +57,8 @@ def test_timeout(self): def test_in_order_messages_are_handled_in_order(self): """Test that messages received in order are handled in order.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -59,10 +70,10 @@ def test_in_order_messages_are_handled_in_order(self): child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) messages = [ - {"event": {"kind": "test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, - {"event": {"kind": "test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, - {"event": {"kind": "test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, - {"event": {"kind": "finish-test"}, "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}}, + {"event": {"kind": "test"}, "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}}, + {"event": {"kind": "test"}, "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}}, + {"event": {"kind": "test"}, "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}}, + {"event": {"kind": "finish-test"}, "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}}, ] for message in messages: @@ -78,6 +89,8 @@ def test_in_order_messages_are_handled_in_order(self): def test_out_of_order_messages_are_handled_in_order(self): """Test that messages received out of order are handled in order.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -91,19 +104,19 @@ def test_out_of_order_messages_are_handled_in_order(self): messages = [ { "event": {"kind": "test", "order": 1}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 2}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 0}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "finish-test", "order": 3}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -129,6 +142,8 @@ def test_out_of_order_messages_with_end_message_first_are_handled_in_order(self) """Test that messages received out of order and with the final message (the message that triggers a value to be returned) are handled in order. """ + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -142,19 +157,19 @@ def test_out_of_order_messages_with_end_message_first_are_handled_in_order(self) messages = [ { "event": {"kind": "finish-test", "order": 3}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 1}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 2}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 0}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -178,6 +193,8 @@ def test_out_of_order_messages_with_end_message_first_are_handled_in_order(self) def test_no_timeout(self): """Test that message handling works with no timeout.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -191,15 +208,15 @@ def test_no_timeout(self): messages = [ { "event": {"kind": "test", "order": 0}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 1}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "finish-test", "order": 2}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -216,6 +233,8 @@ def test_no_timeout(self): def test_delivery_acknowledgement(self): """Test that a delivery acknowledgement message is handled correctly.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -227,11 +246,11 @@ def test_delivery_acknowledgement(self): messages = [ { "event": {"kind": "delivery_acknowledgement", "datetime": datetime.datetime.utcnow().isoformat()}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "result"}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -243,6 +262,8 @@ def test_delivery_acknowledgement(self): def test_error_raised_if_heartbeat_not_received_before_checked(self): """Test that an error is raised if a heartbeat isn't received before a heartbeat is first checked for.""" + question_uuid, _, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) @@ -254,6 +275,8 @@ def test_error_raised_if_heartbeat_not_received_before_checked(self): def test_error_raised_if_heartbeats_stop_being_received(self): """Test that an error is raised if heartbeats stop being received within the maximum interval.""" + question_uuid, _, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -269,6 +292,8 @@ def test_error_raised_if_heartbeats_stop_being_received(self): def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_interval(self): """Test that an error is not raised if a heartbeat has been received in the maximum allowed interval.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -285,11 +310,11 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte "kind": "delivery_acknowledgement", "datetime": datetime.datetime.utcnow().isoformat(), }, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "result"}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -304,6 +329,8 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte def test_time_since_last_heartbeat_is_none_if_no_heartbeat_received_yet(self): """Test that the time since the last heartbeat is `None` if no heartbeat has been received yet.""" + question_uuid, _, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -316,10 +343,12 @@ def test_total_run_time_is_none_if_handle_messages_has_not_been_called(self): """Test that the total run time for the message handler is `None` if the `handle_messages` method has not been called. """ + question_uuid, _, mock_subscription = create_mock_topic_and_subscription() message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) self.assertIsNone(message_handler.total_run_time) def test_time_since_missing_message_is_none_if_no_missing_messages(self): + question_uuid, _, mock_subscription = create_mock_topic_and_subscription() message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) self.assertIsNone(message_handler.time_since_missing_message) @@ -327,6 +356,8 @@ def test_missing_messages_at_start_can_be_skipped(self): """Test that the first n messages can be skipped if they aren't received after a given time period if subsequent messages have been received. """ + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -344,19 +375,19 @@ def test_missing_messages_at_start_can_be_skipped(self): messages = [ { "event": {"kind": "test", "order": 2}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 3}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 4}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "finish-test", "order": 5}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -378,6 +409,8 @@ def test_missing_messages_at_start_can_be_skipped(self): def test_missing_messages_in_middle_can_skipped(self): """Test that missing messages in the middle of the event stream can be skipped.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -393,15 +426,15 @@ def test_missing_messages_in_middle_can_skipped(self): messages = [ { "event": {"kind": "test", "order": 0}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 1}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 2}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -414,7 +447,7 @@ def test_missing_messages_in_middle_can_skipped(self): # Send a final message. child._send_message( message={"kind": "finish-test", "order": 5}, - attributes={"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + attributes={"question_uuid": question_uuid, "sender_type": "CHILD"}, topic=mock_topic, ) @@ -433,6 +466,8 @@ def test_missing_messages_in_middle_can_skipped(self): def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): """Test that multiple blocks of missing messages in the middle of the event stream can be skipped.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -448,15 +483,15 @@ def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): messages = [ { "event": {"kind": "test", "order": 0}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 1}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 2}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -469,7 +504,7 @@ def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): # Send another message. child._send_message( message={"kind": "test", "order": 5}, - attributes={"message_number": 5, "question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + attributes={"message_number": 5, "question_uuid": question_uuid, "sender_type": "CHILD"}, topic=mock_topic, ) @@ -480,19 +515,19 @@ def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): messages = [ { "event": {"kind": "test", "order": 20}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 21}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "test", "order": 22}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, { "event": {"kind": "finish-test", "order": 23}, - "attributes": {"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + "attributes": {"question_uuid": question_uuid, "sender_type": "CHILD"}, }, ] @@ -518,6 +553,8 @@ def test_multiple_blocks_of_missing_messages_in_middle_can_skipped(self): def test_all_messages_missing_apart_from_result(self): """Test that the result message is still handled if all other messages are missing.""" + question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() + with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): message_handler = OrderedMessageHandler( subscription=mock_subscription, @@ -535,7 +572,7 @@ def test_all_messages_missing_apart_from_result(self): # Send the result message. child._send_message( message={"kind": "finish-test", "order": 1000}, - attributes={"question_uuid": QUESTION_UUID, "sender_type": "CHILD"}, + attributes={"question_uuid": question_uuid, "sender_type": "CHILD"}, topic=mock_topic, ) @@ -548,7 +585,7 @@ def test_all_messages_missing_apart_from_result(self): class TestPullAndEnqueueMessage(BaseTestCase): def test_pull_and_enqueue_available_messages(self): """Test that pulling and enqueuing a message works.""" - question_uuid = "4d31bb46-66c4-4e68-831f-e51e17e651ef" + question_uuid, mock_topic, _ = create_mock_topic_and_subscription() with ServicePatcher(): mock_subscription = MockSubscription( @@ -588,7 +625,7 @@ def test_pull_and_enqueue_available_messages(self): def test_timeout_error_raised_if_result_message_not_received_in_time(self): """Test that a timeout error is raised if a result message is not received in time.""" - question_uuid = "4d31bb46-66c4-4e68-831f-e51e17e651ef" + question_uuid, mock_topic, _ = create_mock_topic_and_subscription() with ServicePatcher(): mock_subscription = MockSubscription( From 815acb9e4848cbdecedd4f93e793bba3365f8e7b Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 15:26:58 +0000 Subject: [PATCH 13/40] ENH: Suppress name/namespace override warning if value is the same --- octue/cloud/service_id.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/octue/cloud/service_id.py b/octue/cloud/service_id.py index 92e581388..d314ff18a 100644 --- a/octue/cloud/service_id.py +++ b/octue/cloud/service_id.py @@ -35,7 +35,7 @@ def get_sruid_parts(service_configuration): service_name = os.environ.get("OCTUE_SERVICE_NAME") service_revision_tag = os.environ.get("OCTUE_SERVICE_REVISION_TAG") - if service_namespace: + if service_namespace and service_namespace != service_configuration.namespace: logger.warning( "The namespace in the service configuration %r has been overridden by the `OCTUE_SERVICE_NAMESPACE` " "environment variable %r.", @@ -45,7 +45,7 @@ def get_sruid_parts(service_configuration): else: service_namespace = service_configuration.namespace - if service_name: + if service_name and service_name != service_configuration.name: logger.warning( "The name in the service configuration %r has been overridden by the `OCTUE_SERVICE_NAME` environment " "variable %r.", From 52717aca40f655b993e2608549eb6c576de45519 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 16:48:46 +0000 Subject: [PATCH 14/40] FIX: Exit early from message pulling if heartbeat check fails --- octue/cloud/pub_sub/message_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 98234663d..f671ca874 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -211,7 +211,7 @@ def _pull_and_enqueue_available_messages(self, timeout): pull_start_time = time.perf_counter() attempt = 1 - while True: + while self._alive: logger.debug("Pulling messages from Google Pub/Sub: attempt %d.", attempt) pull_response = self._subscriber.pull( From 0754ad8fd4f7be421085cdb6f77ac3538ea21baf Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 17:43:56 +0000 Subject: [PATCH 15/40] ENH: Cache JSON schema for service event validation --- octue/cloud/validation.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/octue/cloud/validation.py b/octue/cloud/validation.py index 35677a2fe..398bf4842 100644 --- a/octue/cloud/validation.py +++ b/octue/cloud/validation.py @@ -12,6 +12,12 @@ SERVICE_COMMUNICATION_SCHEMA_INFO_URL = "https://strands.octue.com/octue/service-communication" SERVICE_COMMUNICATION_SCHEMA_VERSION = os.path.splitext(SERVICE_COMMUNICATION_SCHEMA)[0].split("/")[-1] +# Instantiate a JSON schema validator to cache the service communication schema to avoid getting it from the bucket +# every time a message is validated against it. +schema = {"$ref": SERVICE_COMMUNICATION_SCHEMA} +jsonschema_validator = jsonschema.Draft202012Validator(schema) +jsonschema_validator.check_schema(schema) + def is_event_valid(event, attributes, receiving_service, parent_sdk_version, child_sdk_version, schema=None): """Check if the event and its attributes are valid according to the Octue services communication schema. @@ -58,11 +64,13 @@ def raise_if_event_is_invalid( :raise jsonschema.ValidationError: if the event or its attributes are invalid :return None: """ - if schema is None: - schema = {"$ref": SERVICE_COMMUNICATION_SCHEMA} + global jsonschema_validator + + if (schema is not None) and (schema != {"$ref": SERVICE_COMMUNICATION_SCHEMA}): + jsonschema_validator = jsonschema.Draft202012Validator(schema=schema) try: - jsonschema.validate({"event": event, "attributes": dict(attributes)}, schema) + jsonschema_validator.validate({"event": event, "attributes": dict(attributes)}) except jsonschema.ValidationError as error: warn_if_incompatible(parent_sdk_version=parent_sdk_version, child_sdk_version=child_sdk_version) From b232eceedc0568f4cfcb90336a5bd9ab6bad1fe4 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 18:00:40 +0000 Subject: [PATCH 16/40] REF: Simplify json schema caching --- octue/cloud/validation.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/octue/cloud/validation.py b/octue/cloud/validation.py index 398bf4842..a1b305e3c 100644 --- a/octue/cloud/validation.py +++ b/octue/cloud/validation.py @@ -64,13 +64,17 @@ def raise_if_event_is_invalid( :raise jsonschema.ValidationError: if the event or its attributes are invalid :return None: """ - global jsonschema_validator - - if (schema is not None) and (schema != {"$ref": SERVICE_COMMUNICATION_SCHEMA}): - jsonschema_validator = jsonschema.Draft202012Validator(schema=schema) + data = {"event": event, "attributes": dict(attributes)} try: - jsonschema_validator.validate({"event": event, "attributes": dict(attributes)}) + # If the schema is the official service communication schema, use the cached validator. + if schema is None or schema == {"$ref": SERVICE_COMMUNICATION_SCHEMA}: + jsonschema_validator.validate(data) + + # Otherwise, use uncached validation. + else: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as error: warn_if_incompatible(parent_sdk_version=parent_sdk_version, child_sdk_version=child_sdk_version) From 1ce91a17dfe74ff6690fa3f1a6a8402932ac9257 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 18:06:55 +0000 Subject: [PATCH 17/40] REF: Simplify default schema logic --- octue/cloud/pub_sub/message_handler.py | 7 ++----- octue/cloud/validation.py | 15 +++++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index f671ca874..a0fd9cd01 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -62,14 +62,11 @@ def __init__( self.handle_monitor_message = handle_monitor_message self.record_messages = record_messages self.service_name = service_name + self.schema = schema + self.skip_missing_messages_after = skip_missing_messages_after self._missing_message_detection_time = None - if isinstance(schema, str): - self.schema = {"$ref": schema} - else: - self.schema = schema - self.question_uuid = self.subscription.path.split(".")[-1] self.handled_messages = [] self.waiting_messages = None diff --git a/octue/cloud/validation.py b/octue/cloud/validation.py index a1b305e3c..385ea11fa 100644 --- a/octue/cloud/validation.py +++ b/octue/cloud/validation.py @@ -8,15 +8,14 @@ logger = logging.getLogger(__name__) -SERVICE_COMMUNICATION_SCHEMA = "https://jsonschema.registry.octue.com/octue/service-communication/0.8.2.json" +SERVICE_COMMUNICATION_SCHEMA = {"$ref": "https://jsonschema.registry.octue.com/octue/service-communication/0.8.2.json"} SERVICE_COMMUNICATION_SCHEMA_INFO_URL = "https://strands.octue.com/octue/service-communication" -SERVICE_COMMUNICATION_SCHEMA_VERSION = os.path.splitext(SERVICE_COMMUNICATION_SCHEMA)[0].split("/")[-1] +SERVICE_COMMUNICATION_SCHEMA_VERSION = os.path.splitext(SERVICE_COMMUNICATION_SCHEMA["$ref"])[0].split("/")[-1] -# Instantiate a JSON schema validator to cache the service communication schema to avoid getting it from the bucket -# every time a message is validated against it. -schema = {"$ref": SERVICE_COMMUNICATION_SCHEMA} -jsonschema_validator = jsonschema.Draft202012Validator(schema) -jsonschema_validator.check_schema(schema) +# Instantiate a JSON schema validator to cache the service communication schema. This avoids getting it from the +# registry every time a message is validated against it. +jsonschema.Draft202012Validator.check_schema(SERVICE_COMMUNICATION_SCHEMA) +jsonschema_validator = jsonschema.Draft202012Validator(SERVICE_COMMUNICATION_SCHEMA) def is_event_valid(event, attributes, receiving_service, parent_sdk_version, child_sdk_version, schema=None): @@ -68,7 +67,7 @@ def raise_if_event_is_invalid( try: # If the schema is the official service communication schema, use the cached validator. - if schema is None or schema == {"$ref": SERVICE_COMMUNICATION_SCHEMA}: + if schema in (None, SERVICE_COMMUNICATION_SCHEMA): jsonschema_validator.validate(data) # Otherwise, use uncached validation. From b0a4e38de28897604b7d73420aea215f87e22f92 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Wed, 31 Jan 2024 18:12:32 +0000 Subject: [PATCH 18/40] TST: Remove extra newlines in class instantiations --- tests/cloud/pub_sub/test_message_handler.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index af4f5f3d0..df0558560 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -236,10 +236,7 @@ def test_delivery_acknowledgement(self): question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): - message_handler = OrderedMessageHandler( - subscription=mock_subscription, - receiving_service=parent, - ) + message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) @@ -278,10 +275,7 @@ def test_error_raised_if_heartbeats_stop_being_received(self): question_uuid, _, mock_subscription = create_mock_topic_and_subscription() with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): - message_handler = OrderedMessageHandler( - subscription=mock_subscription, - receiving_service=parent, - ) + message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) message_handler._last_heartbeat = datetime.datetime.now() - datetime.timedelta(seconds=30) @@ -295,10 +289,7 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): - message_handler = OrderedMessageHandler( - subscription=mock_subscription, - receiving_service=parent, - ) + message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) message_handler._last_heartbeat = datetime.datetime.now() @@ -332,10 +323,7 @@ def test_time_since_last_heartbeat_is_none_if_no_heartbeat_received_yet(self): question_uuid, _, mock_subscription = create_mock_topic_and_subscription() with patch("octue.cloud.pub_sub.message_handler.SubscriberClient", MockSubscriber): - message_handler = OrderedMessageHandler( - subscription=mock_subscription, - receiving_service=parent, - ) + message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) self.assertIsNone(message_handler._time_since_last_heartbeat) From 76667b1009b7166ae6218f8bf1ee5ccd80369931 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 10:31:05 +0000 Subject: [PATCH 19/40] REF: Avoid unnecessary repetition of finding earliest waiting message --- octue/cloud/pub_sub/message_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index a0fd9cd01..0706d102a 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -239,6 +239,8 @@ def _pull_and_enqueue_available_messages(self, timeout): for message in pull_response.received_messages: self._extract_and_enqueue_event(message) + self._earliest_waiting_message_number = min(self.waiting_messages.keys()) + def _extract_and_enqueue_event(self, message): logger.debug("%r received a message related to question %r.", self.receiving_service, self.question_uuid) event, attributes = extract_event_and_attributes_from_pub_sub(message.message) @@ -259,7 +261,6 @@ def _extract_and_enqueue_event(self, message): message_number = attributes["message_number"] self.waiting_messages[message_number] = event - self._earliest_waiting_message_number = min(self.waiting_messages.keys()) def _attempt_to_handle_waiting_messages(self): """Attempt to handle messages waiting in the pulled message queue. If these messages aren't consecutive to the From 1cf1950a75fe13c7c1e3f0bc294bb2507cf6ad70 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 11:25:48 +0000 Subject: [PATCH 20/40] ENH: Extract SRUID for child logs from subscription in message handler BREAKING CHANGE: This removes the `service_name` argument from `Service.wait_for_answer`. If you were using this argument, simply remove it; logs from children shown in a parent will now have the full and correct SRUID automatically. --- octue/cloud/emulators/child.py | 1 - octue/cloud/pub_sub/message_handler.py | 3 +- octue/cloud/pub_sub/service.py | 5 ++-- octue/cloud/service_id.py | 5 ++++ octue/log_handlers.py | 2 +- octue/resources/child.py | 1 - tests/cloud/pub_sub/test_service.py | 40 +++++++++++++++----------- 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/octue/cloud/emulators/child.py b/octue/cloud/emulators/child.py index 4e9f21e9b..71d59a61b 100644 --- a/octue/cloud/emulators/child.py +++ b/octue/cloud/emulators/child.py @@ -126,7 +126,6 @@ def ask( subscription, handle_monitor_message=handle_monitor_message, record_messages=record_messages, - service_name=self.id, timeout=timeout, ) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 0706d102a..a4acab3db 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -380,8 +380,7 @@ def _handle_log_message(self, message): text_colour=self._log_message_colours[0], ) - # Colour any analysis sections from children of the immediate child with the rest of the colour palette and - # colour the message from the furthest child white. + # Colour any analysis sections from children of the immediate child with the rest of the colour palette. subchild_analysis_sections = [section.strip("[") for section in re.split("] ", record.msg)] final_message = subchild_analysis_sections.pop(-1) diff --git a/octue/cloud/pub_sub/service.py b/octue/cloud/pub_sub/service.py index f7e6d1959..c78415ed2 100644 --- a/octue/cloud/pub_sub/service.py +++ b/octue/cloud/pub_sub/service.py @@ -22,6 +22,7 @@ convert_service_id_to_pub_sub_form, create_sruid, get_default_sruid, + get_sruid_from_pub_sub_resource_name, raise_if_revision_not_registered, split_service_id, validate_sruid, @@ -371,7 +372,6 @@ def wait_for_answer( subscription, handle_monitor_message=None, record_messages=True, - service_name="REMOTE", timeout=60, maximum_heartbeat_interval=300, ): @@ -381,7 +381,6 @@ def wait_for_answer( :param octue.cloud.pub_sub.subscription.Subscription subscription: the subscription for the question's answer :param callable|None handle_monitor_message: a function to handle monitor messages (e.g. send them to an endpoint for plotting or displaying) - this function should take a single JSON-compatible python primitive as an argument (note that this could be an array or object) :param bool record_messages: if `True`, record messages received from the child in the `received_messages` attribute - :param str service_name: a name by which to refer to the child subscribed to (used for labelling its log messages if subscribed to) :param float|None timeout: how long in seconds to wait for an answer before raising a `TimeoutError` :param float|int delivery_acknowledgement_timeout: how long in seconds to wait for a delivery acknowledgement before aborting :param float|int maximum_heartbeat_interval: the maximum amount of time (in seconds) allowed between child heartbeats before an error is raised @@ -394,6 +393,8 @@ def wait_for_answer( f"its push endpoint at {subscription.push_endpoint!r}." ) + service_name = get_sruid_from_pub_sub_resource_name(subscription.name) + self._message_handler = OrderedMessageHandler( subscription=subscription, receiving_service=self, diff --git a/octue/cloud/service_id.py b/octue/cloud/service_id.py index d314ff18a..fc47cebe9 100644 --- a/octue/cloud/service_id.py +++ b/octue/cloud/service_id.py @@ -209,6 +209,11 @@ def convert_service_id_to_pub_sub_form(service_id): return service_id +def get_sruid_from_pub_sub_resource_name(name): + _, _, namespace, name, revision_tag, *_ = name.split(".") + return f"{namespace}/{name}:{revision_tag.replace('-', '.')}" + + def split_service_id(service_id, require_revision_tag=False): """Split an SRUID or service ID into its namespace, name, and, if present, its revision tag. The split parts are validated before being returned. diff --git a/octue/log_handlers.py b/octue/log_handlers.py index 5fce97d55..2e5be01f9 100644 --- a/octue/log_handlers.py +++ b/octue/log_handlers.py @@ -196,7 +196,7 @@ def get_log_record_attributes_for_environment(): :return list: """ if os.environ.get("COMPUTE_PROVIDER", "UNKNOWN") in GOOGLE_COMPUTE_PROVIDERS: - return LOG_RECORD_ATTRIBUTES_WITH_TIMESTAMP[1:] + return LOG_RECORD_ATTRIBUTES_WITHOUT_TIMESTAMP return LOG_RECORD_ATTRIBUTES_WITH_TIMESTAMP diff --git a/octue/resources/child.py b/octue/resources/child.py index d5e0a11a0..86dc45d7d 100644 --- a/octue/resources/child.py +++ b/octue/resources/child.py @@ -100,7 +100,6 @@ def ask( subscription=subscription, handle_monitor_message=handle_monitor_message, record_messages=record_messages, - service_name=self.id, timeout=timeout, maximum_heartbeat_interval=maximum_heartbeat_interval, ) diff --git a/tests/cloud/pub_sub/test_service.py b/tests/cloud/pub_sub/test_service.py index d9a96a4bd..93abbc3fc 100644 --- a/tests/cloud/pub_sub/test_service.py +++ b/tests/cloud/pub_sub/test_service.py @@ -169,8 +169,14 @@ def test_ask_service_with_no_revision_tag_when_service_registries_not_specified_ def test_timeout_error_raised_if_no_messages_received_when_waiting(self): """Test that a TimeoutError is raised if no messages are received while waiting.""" - mock_topic = MockTopic(name="world", project_name=TEST_PROJECT_NAME) - mock_subscription = MockSubscription(name="world", topic=mock_topic, project_name=TEST_PROJECT_NAME) + mock_topic = MockTopic(name="amazing.service.9-9-9", project_name=TEST_PROJECT_NAME) + + mock_subscription = MockSubscription( + name="amazing.service.9-9-9", + topic=mock_topic, + project_name=TEST_PROJECT_NAME, + ) + service = Service(backend=BACKEND) with patch("octue.cloud.pub_sub.service.pubsub_v1.SubscriberClient.pull", return_value=MockPullResponse()): @@ -269,14 +275,19 @@ def test_ask_with_real_run_function_with_log_message_forwarding(self): run function rather than a mock so that the underlying `Runner` instance is used, and check that remote log messages are forwarded to the local logger. """ - child = MockService(backend=BACKEND, run_function=self.create_run_function()) + child = MockService( + backend=BACKEND, + service_id="my-super/service:6.0.1", + run_function=self.create_run_function(), + ) + parent = MockService(backend=BACKEND, children={child.id: child}) with self.assertLogs() as logs_context_manager: with self.service_patcher: child.serve() subscription, _ = parent.ask(service_id=child.id, input_values={}, subscribe_to_logs=True) - answer = parent.wait_for_answer(subscription, service_name="my-super-service") + answer = parent.wait_for_answer(subscription) self.assertEqual( answer, @@ -289,11 +300,11 @@ def test_ask_with_real_run_function_with_log_message_forwarding(self): finish_remote_analysis_message_present = False for i, log_record in enumerate(logs_context_manager.records): - if "[my-super-service" in log_record.msg and "Starting analysis." in log_record.msg: + if "[my-super/service:6.0.1" in log_record.msg and "Starting analysis." in log_record.msg: start_remote_analysis_message_present = True if ( - "[my-super-service" in logs_context_manager.records[i + 1].msg + "[my-super/service:6.0.1" in logs_context_manager.records[i + 1].msg and "Finished analysis." in logs_context_manager.records[i + 1].msg ): finish_remote_analysis_message_present = True @@ -322,7 +333,7 @@ def mock_app(analysis): with self.service_patcher: child.serve() subscription, _ = parent.ask(service_id=child.id, input_values={}, subscribe_to_logs=True) - parent.wait_for_answer(subscription, service_name="my-super-service") + parent.wait_for_answer(subscription) error_logged = False @@ -436,7 +447,7 @@ def run_function(analysis_id, input_values, *args, **kwargs): save_diagnostics="SAVE_DIAGNOSTICS_ON_CRASH", ) - answer = parent.wait_for_answer(subscription, service_name="my-super-service") + answer = parent.wait_for_answer(subscription) self.assertEqual(answer["output_values"], input_values) @@ -712,7 +723,7 @@ def test_child_messages_can_be_recorded_by_parent(self): with self.service_patcher: child.serve() subscription, _ = parent.ask(service_id=child.id, input_values={}, subscribe_to_logs=True) - parent.wait_for_answer(subscription, service_name="my-super-service") + parent.wait_for_answer(subscription) # Check that the child's messages have been recorded by the parent. self.assertEqual(parent.received_messages[0]["kind"], "delivery_acknowledgement") @@ -731,7 +742,7 @@ def test_child_exception_message_can_be_recorded_by_parent(self): with self.assertRaises(ValueError): subscription, _ = parent.ask(service_id=child.id, input_values={}, subscribe_to_logs=True) - parent.wait_for_answer(subscription, service_name="my-super-service") + parent.wait_for_answer(subscription) # Check that the child's messages have been recorded by the parent. self.assertEqual(parent.received_messages[0]["kind"], "delivery_acknowledgement") @@ -763,7 +774,7 @@ def run_function(*args, **kwargs): save_diagnostics="SAVE_DIAGNOSTICS_ON_CRASH", ) - parent.wait_for_answer(subscription, service_name="my-super-service") + parent.wait_for_answer(subscription) self.assertEqual(parent.received_messages[1]["kind"], "heartbeat") self.assertEqual(parent.received_messages[2]["kind"], "heartbeat") @@ -807,12 +818,7 @@ def run_function(*args, **kwargs): ) monitor_messages = [] - - result = parent.wait_for_answer( - subscription, - service_name="my-super-service", - handle_monitor_message=monitor_messages.append, - ) + result = parent.wait_for_answer(subscription, handle_monitor_message=monitor_messages.append) # Check that multiple monitor messages were sent and received. self.assertTrue(len(monitor_messages) > 1) From 43cba7b3fa646dce57d942076a76f76529662248 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 11:34:12 +0000 Subject: [PATCH 21/40] FIX: Avoid trying to find earliest message when there are none --- octue/cloud/pub_sub/message_handler.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index a4acab3db..83a68e119 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -236,6 +236,9 @@ def _pull_and_enqueue_available_messages(self, timeout): } ) + if not pull_response.received_messages: + return + for message in pull_response.received_messages: self._extract_and_enqueue_event(message) From adaf695ca4acf4156274bbf485dd8364d5fa23e4 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 11:37:12 +0000 Subject: [PATCH 22/40] TST: Update test --- tests/cloud/pub_sub/test_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cloud/pub_sub/test_service.py b/tests/cloud/pub_sub/test_service.py index 93abbc3fc..9ae63cbfb 100644 --- a/tests/cloud/pub_sub/test_service.py +++ b/tests/cloud/pub_sub/test_service.py @@ -254,7 +254,7 @@ def test_ask_with_real_run_function_with_no_log_message_forwarding(self): run function rather than a mock so that the underlying `Runner` instance is used, and check that remote log messages aren't forwarded to the local logger. """ - child = MockService(backend=BACKEND, run_function=self.create_run_function()) + child = MockService(backend=BACKEND, service_id="truly/madly:deeply", run_function=self.create_run_function()) parent = MockService(backend=BACKEND, children={child.id: child}) with self.assertLogs() as logging_context: @@ -268,7 +268,7 @@ def test_ask_with_real_run_function_with_no_log_message_forwarding(self): {"output_values": MockAnalysis().output_values, "output_manifest": MockAnalysis().output_manifest}, ) - self.assertTrue(all("[REMOTE]" not in message for message in logging_context.output)) + self.assertTrue(all("[truly/madly:deeply" not in message for message in logging_context.output)) def test_ask_with_real_run_function_with_log_message_forwarding(self): """Test that a service can ask a question to another service that is serving and receive an answer. Use a real From e9d5d9220756d6b11a8ad67e70de30c0b0cd517a Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 14:15:12 +0000 Subject: [PATCH 23/40] FIX: Make `Manifest.update_dataset_paths` method thread-safe --- octue/cloud/pub_sub/service.py | 7 ++++++- octue/resources/manifest.py | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/octue/cloud/pub_sub/service.py b/octue/cloud/pub_sub/service.py index c78415ed2..5f6c27f70 100644 --- a/octue/cloud/pub_sub/service.py +++ b/octue/cloud/pub_sub/service.py @@ -35,6 +35,10 @@ logger = logging.getLogger(__name__) + +# A lock to ensure only one message can be sent at a time so that the message number is incremented correctly when +# messages are being sent on multiple threads (e.g. via the main thread and a periodic monitor message thread). This +# avoids 1) messages overwriting each other in the parent's message handler and 2) messages losing their order. send_message_lock = threading.Lock() DEFAULT_NAMESPACE = "default" @@ -436,7 +440,8 @@ def send_exception(self, topic, question_uuid, timeout=30): ) def _send_message(self, message, topic, attributes=None, timeout=30): - """Send a JSON-serialised message to the given topic with optional message attributes. + """Send a JSON-serialised message to the given topic with optional message attributes and increment the + `messages_published` attribute of the topic by one. This method is thread-safe. :param dict message: JSON-serialisable data to send as a message :param octue.cloud.pub_sub.topic.Topic topic: the Pub/Sub topic to send the message to diff --git a/octue/resources/manifest.py b/octue/resources/manifest.py index 883130ba9..2fc246315 100644 --- a/octue/resources/manifest.py +++ b/octue/resources/manifest.py @@ -2,6 +2,7 @@ import copy import json import logging +import threading from octue.cloud import storage from octue.cloud.storage import GoogleCloudStorageClient @@ -12,6 +13,12 @@ logger = logging.getLogger(__name__) +# A lock to ensure only one thread can use the `Manifest.update_dataset_paths` method at a time. This avoids a race +# condition where a manifest shared across multiple questions in e.g. `Child.ask_multiple` has its dataset paths +# updated by more than one thread simultaneously while attempting to convert them to signed URLs. This lock should +# perhaps be applied to all methods where mutations are made to the manifest instead of just this single method. +update_dataset_paths_lock = threading.Lock() + class Manifest(Serialisable, Identifiable, Hashable, Metadata): """A representation of a manifest, which can contain multiple datasets This is used to manage all files coming into @@ -60,17 +67,19 @@ def all_datasets_are_in_cloud(self): return all(dataset.all_files_are_in_cloud for dataset in self.datasets.values()) def update_dataset_paths(self, path_generator): - """Update the path of each dataset according to the given path generator function. + """Update the path of each dataset according to the given path generator function. This method is thread-safe. :param callable path_generator: a function taking a `Dataset` as its only argument and returning the new path of the dataset :return None: """ - for name, dataset in self.datasets.items(): - self.datasets[name].path = path_generator(dataset) + with update_dataset_paths_lock: + for name, dataset in self.datasets.items(): + self.datasets[name].path = path_generator(dataset) def use_signed_urls_for_datasets(self): """Generate signed URLs for any cloud datasets in the manifest and use these as their paths instead of regular - cloud paths. URLs will not be generated for any local datasets in the manifest. This method is idempotent. + cloud paths. URLs will not be generated for any local datasets or datasets whose paths are already URLs + (including those whose paths are already signed), making this method idempotent. :return None: """ From 2e084da15cde657ab8a81bf2822fdc268ce0d9ff Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 17:42:53 +0000 Subject: [PATCH 24/40] OPS: Increase minor version number --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3d3105dda..24c706077 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "octue" -version = "0.51.1" +version = "0.52.0" description = "A package providing template applications for data services, and a python SDK to the Octue API." readme = "README.md" authors = ["Marcus Lugg ", "Thomas Clark "] From 4eca065ce0223a92cac9bfb9b421b0c94603599c Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 17:49:21 +0000 Subject: [PATCH 25/40] REF: Simplify `schema` default argument in `raise_if_event_is_invalid` --- octue/cloud/validation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/octue/cloud/validation.py b/octue/cloud/validation.py index 385ea11fa..456e70c5b 100644 --- a/octue/cloud/validation.py +++ b/octue/cloud/validation.py @@ -64,10 +64,11 @@ def raise_if_event_is_invalid( :return None: """ data = {"event": event, "attributes": dict(attributes)} + schema = schema or SERVICE_COMMUNICATION_SCHEMA try: # If the schema is the official service communication schema, use the cached validator. - if schema in (None, SERVICE_COMMUNICATION_SCHEMA): + if schema == SERVICE_COMMUNICATION_SCHEMA: jsonschema_validator.validate(data) # Otherwise, use uncached validation. From 336d9baea8df6253f65425fee294d4c7a1d35555 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Thu, 1 Feb 2024 17:55:39 +0000 Subject: [PATCH 26/40] DOC: Add docstring to `get_sruid_from_pub_sub_resource_name` skipci --- octue/cloud/service_id.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/octue/cloud/service_id.py b/octue/cloud/service_id.py index fc47cebe9..fa2e021a8 100644 --- a/octue/cloud/service_id.py +++ b/octue/cloud/service_id.py @@ -210,6 +210,12 @@ def convert_service_id_to_pub_sub_form(service_id): def get_sruid_from_pub_sub_resource_name(name): + """Get the SRUID from a Google Pub/Sub topic or subscription name. Note that any hyphens in the revision tag will + be replaced with periods. + + :param str name: the name of the topic or subscription + :return str: the SRUID of the service revision the topic or subscription is related to + """ _, _, namespace, name, revision_tag, *_ = name.split(".") return f"{namespace}/{name}:{revision_tag.replace('-', '.')}" From 3adfc45af94fae49580cd2f00f82d80c4cfa4382 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 10:59:48 +0000 Subject: [PATCH 27/40] ENH: Log number of missing messages when they're skipped --- octue/cloud/pub_sub/message_handler.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 83a68e119..8e02fc769 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -311,13 +311,16 @@ def _skip_to_earliest_waiting_message(self): except KeyError: return + number_of_missing_messages = self._earliest_waiting_message_number - self._previous_message_number + 1 + # Let the message handler know it can handle the next earliest message. self._previous_message_number = self._earliest_waiting_message_number - 1 logger.warning( - "%r: Some messages for question %r weren't received after %ds - skipping to the next earliest received " + "%r: %d messages for question %r weren't received after %ds - skipping to the next earliest received " "message (message number %d).", self.receiving_service, + number_of_missing_messages, self.question_uuid, self.skip_missing_messages_after, self._earliest_waiting_message_number, From eb36b82bbc59a1774fd3462a1b8f26624a39cf37 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 11:00:13 +0000 Subject: [PATCH 28/40] ENH: Decrease missing message waiting time from 60s to 10s --- octue/cloud/pub_sub/message_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 8e02fc769..2e1a15e40 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -55,7 +55,7 @@ def __init__( service_name="REMOTE", message_handlers=None, schema=SERVICE_COMMUNICATION_SCHEMA, - skip_missing_messages_after=60, + skip_missing_messages_after=10, ): self.subscription = subscription self.receiving_service = receiving_service From 39168e102f6b8062b52cb2fbaffd0b4bf02364d7 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 11:09:05 +0000 Subject: [PATCH 29/40] ENH: Improve missing messages log message --- octue/cloud/pub_sub/message_handler.py | 6 +++--- tests/cloud/pub_sub/test_message_handler.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 2e1a15e40..986f5b2a8 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -311,14 +311,14 @@ def _skip_to_earliest_waiting_message(self): except KeyError: return - number_of_missing_messages = self._earliest_waiting_message_number - self._previous_message_number + 1 + number_of_missing_messages = self._earliest_waiting_message_number - self._previous_message_number - 1 # Let the message handler know it can handle the next earliest message. self._previous_message_number = self._earliest_waiting_message_number - 1 logger.warning( - "%r: %d messages for question %r weren't received after %ds - skipping to the next earliest received " - "message (message number %d).", + "%r: %d consecutive messages missing for question %r after %ds - skipping to next earliest received " + "message (message %d).", self.receiving_service, number_of_missing_messages, self.question_uuid, diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index df0558560..661dadd52 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -355,7 +355,7 @@ def test_missing_messages_at_start_can_be_skipped(self): skip_missing_messages_after=0, ) - # Simulate the first two messages not being received. + # Simulate the first three messages not being received. mock_topic.messages_published = 2 child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) From 5441537a757c0b58ffe08f85707125b247289194 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 11:09:30 +0000 Subject: [PATCH 30/40] FIX: Allow empty schemas in `validation` module --- octue/cloud/validation.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/octue/cloud/validation.py b/octue/cloud/validation.py index 456e70c5b..98137651e 100644 --- a/octue/cloud/validation.py +++ b/octue/cloud/validation.py @@ -64,7 +64,9 @@ def raise_if_event_is_invalid( :return None: """ data = {"event": event, "attributes": dict(attributes)} - schema = schema or SERVICE_COMMUNICATION_SCHEMA + + if schema is None: + schema = SERVICE_COMMUNICATION_SCHEMA try: # If the schema is the official service communication schema, use the cached validator. From 5840dee70ea0da1c37939ce61aad4990d3b069d6 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 11:26:46 +0000 Subject: [PATCH 31/40] TST: Correct comment in test --- tests/cloud/pub_sub/test_message_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index 661dadd52..df0558560 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -355,7 +355,7 @@ def test_missing_messages_at_start_can_be_skipped(self): skip_missing_messages_after=0, ) - # Simulate the first three messages not being received. + # Simulate the first two messages not being received. mock_topic.messages_published = 2 child = MockService(backend=GCPPubSubBackend(project_name=TEST_PROJECT_NAME)) From dd686071b085f71826b61b94e82dea70ed65cf85 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 11:39:12 +0000 Subject: [PATCH 32/40] DOC: Add new `Child.ask_multiple` argument to docs --- docs/source/asking_questions.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/asking_questions.rst b/docs/source/asking_questions.rst index 129cf59d9..a792a2f79 100644 --- a/docs/source/asking_questions.rst +++ b/docs/source/asking_questions.rst @@ -89,6 +89,10 @@ Options: times - If ``raise_errors=False`` is provided with ``max_retries > 0`` and ``prevent_retries_when`` is set to a list of exception types, failed questions are retried except for those whose exception types are in the list +- The maximum number of threads that can be used to ask questions in parallel can be set via the + ``max_parallel_questions`` argument. This has no effect on the total number of questions that can be given to + ``Child.ask_multiple`` - any number of questions can be enqueued; this option just controls the maximum number + processed from the queue at once. Asking a question within a service From f69a9f37f28ec2f041c6af1089add4c9d8a8a4c8 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 11:51:51 +0000 Subject: [PATCH 33/40] ENH: Allow any number to be set for `max_workers` in `ask_multiple` --- octue/resources/child.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/octue/resources/child.py b/octue/resources/child.py index 86dc45d7d..7ac6ec839 100644 --- a/octue/resources/child.py +++ b/octue/resources/child.py @@ -1,6 +1,7 @@ import concurrent.futures import copy import logging +import os from octue.cloud.pub_sub.service import Service from octue.resources import service_backends @@ -9,7 +10,6 @@ logger = logging.getLogger(__name__) BACKEND_TO_SERVICE_MAPPING = {"GCPPubSubBackend": Service} -MAX_PARALLEL_QUESTIONS = 32 class Child: @@ -104,14 +104,7 @@ def ask( maximum_heartbeat_interval=maximum_heartbeat_interval, ) - def ask_multiple( - self, - *questions, - raise_errors=True, - max_retries=0, - prevent_retries_when=None, - max_parallel_questions=MAX_PARALLEL_QUESTIONS, - ): + def ask_multiple(self, *questions, raise_errors=True, max_retries=0, prevent_retries_when=None, max_workers=None): """Ask the child multiple questions in parallel and wait for the answers. Each question should be provided as a dictionary of `Child.ask` keyword arguments. If `raise_errors` is `True`, an error is raised and no answers are returned if any of the individual questions raise an error; if it's `False`, answers are returned for all @@ -121,21 +114,16 @@ def ask_multiple( :param bool raise_errors: if `True`, an error is raised and no answers are returned if any of the individual questions raise an error; if `False`, answers are returned for all successful questions while errors are returned unraised for any failed ones :param int max_retries: retry any questions that failed up to this number of times (note: this will have no effect unless `raise_errors=False`) :param list(type)|None prevent_retries_when: prevent retrying any questions that fail with an exception type in this list (note: this will have no effect unless `raise_errors=False`) - :param int max_parallel_questions: the maximum number of questions that can be asked at once + :param int|None max_workers: the maximum number of questions that can be asked at once; defaults to `min(32, os.cpu_count() + 4, len(questions))` (see `concurrent.futures.ThreadPoolExecutor`) :raise ValueError: if the maximum number of parallel questions is set too high :raise Exception: if any question raises an error if `raise_errors` is `True` :return list: the answers or caught errors of the questions in the same order as asked """ - if max_parallel_questions > MAX_PARALLEL_QUESTIONS: - raise ValueError( - f"The maximum number of parallel questions cannot be above {MAX_PARALLEL_QUESTIONS}; received {max_parallel_questions}." - ) - prevent_retries_when = prevent_retries_when or [] # Answers will come out of order, so use a dictionary to store them against their questions' original index. answers = {} - max_workers = min(max_parallel_questions, len(questions)) + max_workers = max_workers or min(32, os.cpu_count() + 4, len(questions)) logger.info("Asking %d questions.", len(questions)) with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: From 38a3ac79257ebf39d9abb4f5b10c6bbda9d211b4 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 14:10:37 +0000 Subject: [PATCH 34/40] REF: Make `_pull_and_enqueue_available_messages` return earlier --- octue/cloud/pub_sub/message_handler.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 986f5b2a8..9b4907ad4 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -104,6 +104,11 @@ def total_run_time(self): @property def time_since_missing_message(self): + """Get the amount of time elapsed since the last missing message was detected. If no missing messages have been + detected or they've already been skipped past, `None` is returned. + + :return float|None: + """ if self._missing_message_detection_time is None: return None @@ -229,6 +234,9 @@ def _pull_and_enqueue_available_messages(self, timeout): f"No message received from topic {self.subscription.topic.path!r} after {timeout} seconds.", ) + if not pull_response.received_messages: + return + self._subscriber.acknowledge( request={ "subscription": self.subscription.path, @@ -236,9 +244,6 @@ def _pull_and_enqueue_available_messages(self, timeout): } ) - if not pull_response.received_messages: - return - for message in pull_response.received_messages: self._extract_and_enqueue_event(message) From 618fd49291a9ae9b15878d51a48c807f0ca1660d Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 14:17:53 +0000 Subject: [PATCH 35/40] DOC: Improve message handler docstrings --- octue/cloud/pub_sub/message_handler.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index 9b4907ad4..b64532b3a 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -250,6 +250,11 @@ def _pull_and_enqueue_available_messages(self, timeout): self._earliest_waiting_message_number = min(self.waiting_messages.keys()) def _extract_and_enqueue_event(self, message): + """Extract an event from the Pub/Sub message and add it to `self.waiting_messages`. + + :param dict message: + :return None: + """ logger.debug("%r received a message related to question %r.", self.receiving_service, self.question_uuid) event, attributes = extract_event_and_attributes_from_pub_sub(message.message) @@ -271,10 +276,10 @@ def _extract_and_enqueue_event(self, message): self.waiting_messages[message_number] = event def _attempt_to_handle_waiting_messages(self): - """Attempt to handle messages waiting in the pulled message queue. If these messages aren't consecutive to the + """Attempt to handle messages waiting in `self.waiting_messages`. If these messages aren't consecutive to the last handled message (i.e. if messages have been received out of order and the next in-order message hasn't been - received yet), just return. After the given amount of time, if the first n messages haven't arrived but - subsequent ones have, skip to the earliest received message and continue from there. + received yet), just return. After the missing message wait time has passed, if this set of missing messages + haven't arrived but subsequent ones have, skip to the earliest waiting message and continue from there. :return any|None: either a non-`None` result from a message handler or `None` if nothing was returned by the message handlers or if the next in-order message hasn't been received yet """ From 1222e83ebf496f7113ac575218bc3994903fb958 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 14:19:20 +0000 Subject: [PATCH 36/40] ENH: Improve log message --- octue/cloud/pub_sub/message_handler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/octue/cloud/pub_sub/message_handler.py b/octue/cloud/pub_sub/message_handler.py index b64532b3a..8385539d7 100644 --- a/octue/cloud/pub_sub/message_handler.py +++ b/octue/cloud/pub_sub/message_handler.py @@ -327,8 +327,8 @@ def _skip_to_earliest_waiting_message(self): self._previous_message_number = self._earliest_waiting_message_number - 1 logger.warning( - "%r: %d consecutive messages missing for question %r after %ds - skipping to next earliest received " - "message (message %d).", + "%r: %d consecutive messages missing for question %r after %ds - skipping to next earliest waiting message " + "(message %d).", self.receiving_service, number_of_missing_messages, self.question_uuid, From 2ca04d8070e813b45c06acfa7836445db9056cd7 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 14:37:30 +0000 Subject: [PATCH 37/40] TST: Improve test docstrings --- tests/cloud/pub_sub/test_message_handler.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/cloud/pub_sub/test_message_handler.py b/tests/cloud/pub_sub/test_message_handler.py index df0558560..fe10a290f 100644 --- a/tests/cloud/pub_sub/test_message_handler.py +++ b/tests/cloud/pub_sub/test_message_handler.py @@ -335,14 +335,17 @@ def test_total_run_time_is_none_if_handle_messages_has_not_been_called(self): message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) self.assertIsNone(message_handler.total_run_time) - def test_time_since_missing_message_is_none_if_no_missing_messages(self): + def test_time_since_missing_message_is_none_if_no_unhandled_missing_messages(self): + """Test that the `OrderedMessageHandler.time_since_missing_message` property is `None` if there are no unhandled + missing messages. + """ question_uuid, _, mock_subscription = create_mock_topic_and_subscription() message_handler = OrderedMessageHandler(subscription=mock_subscription, receiving_service=parent) self.assertIsNone(message_handler.time_since_missing_message) def test_missing_messages_at_start_can_be_skipped(self): - """Test that the first n messages can be skipped if they aren't received after a given time period if subsequent - messages have been received. + """Test that missing messages at the start of the event stream can be skipped if they aren't received after a + given time period if subsequent messages have been received. """ question_uuid, mock_topic, mock_subscription = create_mock_topic_and_subscription() @@ -570,7 +573,7 @@ def test_all_messages_missing_apart_from_result(self): self.assertEqual(message_handler.handled_messages, [{"kind": "finish-test", "order": 1000}]) -class TestPullAndEnqueueMessage(BaseTestCase): +class TestPullAndEnqueueAvailableMessages(BaseTestCase): def test_pull_and_enqueue_available_messages(self): """Test that pulling and enqueuing a message works.""" question_uuid, mock_topic, _ = create_mock_topic_and_subscription() From d52183238e0db07fadeb1a26cecb013b5cbdaf16 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 14:40:38 +0000 Subject: [PATCH 38/40] DOC: Fix documentation skipci --- docs/source/asking_questions.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/source/asking_questions.rst b/docs/source/asking_questions.rst index a792a2f79..7ca817221 100644 --- a/docs/source/asking_questions.rst +++ b/docs/source/asking_questions.rst @@ -89,10 +89,8 @@ Options: times - If ``raise_errors=False`` is provided with ``max_retries > 0`` and ``prevent_retries_when`` is set to a list of exception types, failed questions are retried except for those whose exception types are in the list -- The maximum number of threads that can be used to ask questions in parallel can be set via the - ``max_parallel_questions`` argument. This has no effect on the total number of questions that can be given to - ``Child.ask_multiple`` - any number of questions can be enqueued; this option just controls the maximum number - processed from the queue at once. +- The maximum number of threads that can be used to ask questions in parallel can be set via the ``max_workers`` + argument. This has no effect on the total number of questions that can be asked via ``Child.ask_multiple``. Asking a question within a service From 22fe46ded506f13cce413b64f65006a40565c6ea Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 15:40:26 +0000 Subject: [PATCH 39/40] CHO: Add version compatibility metadata --- docs/source/inter_service_compatibility.rst | 180 ++++++++++---------- octue/metadata/recorded_questions.jsonl | 3 + octue/metadata/version_compatibilities.json | 175 ++++++++++++++----- 3 files changed, 226 insertions(+), 132 deletions(-) diff --git a/docs/source/inter_service_compatibility.rst b/docs/source/inter_service_compatibility.rst index 11cdd1bec..70cacc724 100644 --- a/docs/source/inter_service_compatibility.rst +++ b/docs/source/inter_service_compatibility.rst @@ -16,92 +16,94 @@ able to accept a question. - ``0`` = incompatible - ``1`` = compatible -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| | 0.51.0 | 0.50.1 | 0.50.0 | 0.49.2 | 0.49.1 | 0.49.0 | 0.48.0 | 0.47.2 | 0.47.1 | 0.47.0 | 0.46.3 | 0.46.2 | 0.46.1 | 0.46.0 | 0.45.0 | 0.44.0 | 0.43.7 | 0.43.6 | 0.43.5 | 0.43.4 | 0.43.3 | 0.43.2 | 0.43.1 | 0.43.0 | 0.42.1 | 0.42.0 | 0.41.1 | 0.41.0 | 0.40.2 | 0.40.1 | 0.40.0 | 0.39.0 | 0.38.1 | 0.38.0 | 0.37.0 | 0.36.0 | 0.35.0 | 0.34.1 | 0.34.0 | 0.33.0 | 0.32.0 | 0.31.0 | 0.30.0 | -+========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+ -| 0.51.0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.50.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.50.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.49.2 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.49.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.49.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.48.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.47.2 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.47.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.47.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.46.3 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.46.2 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.46.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.46.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.45.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.44.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.7 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.6 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.5 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.4 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.3 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.2 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.43.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.42.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.42.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.41.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.41.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.40.2 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.40.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.40.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.39.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.38.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.38.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.37.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.36.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.35.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.34.1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.34.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.33.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.32.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.31.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ -| 0.30.0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -+--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| | 0.52.0 | 0.51.0 | 0.50.1 | 0.50.0 | 0.49.2 | 0.49.1 | 0.49.0 | 0.48.0 | 0.47.2 | 0.47.1 | 0.47.0 | 0.46.3 | 0.46.2 | 0.46.1 | 0.46.0 | 0.45.0 | 0.44.0 | 0.43.7 | 0.43.6 | 0.43.5 | 0.43.4 | 0.43.3 | 0.43.2 | 0.43.1 | 0.43.0 | 0.42.1 | 0.42.0 | 0.41.1 | 0.41.0 | 0.40.2 | 0.40.1 | 0.40.0 | 0.39.0 | 0.38.1 | 0.38.0 | 0.37.0 | 0.36.0 | 0.35.0 | 0.34.1 | 0.34.0 | 0.33.0 | 0.32.0 | 0.31.0 | 0.30.0 | ++========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+==========+ +| 0.52.0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.51.0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.50.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.50.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.49.2 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.49.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.49.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.48.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.47.2 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.47.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.47.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.46.3 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.46.2 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.46.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.46.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.45.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.44.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.7 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.6 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.5 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.4 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.3 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.2 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.43.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.42.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.42.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.41.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.41.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.40.2 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.40.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.40.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.39.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.38.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.38.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.37.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.36.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.35.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.34.1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.34.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.33.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.32.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.31.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ +| 0.30.0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ++--------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+ diff --git a/octue/metadata/recorded_questions.jsonl b/octue/metadata/recorded_questions.jsonl index 964913905..e0378d339 100644 --- a/octue/metadata/recorded_questions.jsonl +++ b/octue/metadata/recorded_questions.jsonl @@ -39,3 +39,6 @@ {"parent_sdk_version": "0.49.1", "question": {"data": "{\"input_values\": {\"height\": 4, \"width\": 72}, \"input_manifest\": {\"id\": \"34216d6d-e32e-4c40-8b05-ee9bd71966c9\", \"name\": null, \"datasets\": {\"my_dataset\": \"/var/folders/sk/hf5fbp616c77tsys9lz55qn40000gp/T/tmppi1e5t2n\"}}, \"children\": null, \"message_number\": 0}", "attributes": {"question_uuid": "3b1224da-8e7f-4b1b-8ef3-c5cf1a5e698c", "forward_logs": "1", "allow_save_diagnostics_data_on_crash": "1", "octue_sdk_version": "0.49.1"}}} {"parent_sdk_version": "0.49.2", "question": {"data": "{\"input_values\": {\"height\": 4, \"width\": 72}, \"input_manifest\": {\"id\": \"bdadcd12-a51b-4571-9db3-9d240bd15faa\", \"name\": null, \"datasets\": {\"my_dataset\": \"/var/folders/sk/hf5fbp616c77tsys9lz55qn40000gp/T/tmpw3232ii0\"}}, \"children\": null, \"message_number\": 0}", "attributes": {"question_uuid": "0b57da2c-38e2-4f8b-9368-fe35125da8fb", "forward_logs": "1", "allow_save_diagnostics_data_on_crash": "1", "octue_sdk_version": "0.49.2"}}} {"parent_sdk_version": "0.50.0", "question": {"data": "{\"input_values\": {\"height\": 4, \"width\": 72}, \"input_manifest\": {\"id\": \"2d618d16-2a2b-437b-8db7-d5139e1645f2\", \"name\": null, \"datasets\": {\"my_dataset\": \"/var/folders/sk/hf5fbp616c77tsys9lz55qn40000gp/T/tmpr7jpj4sp\"}}, \"children\": null, \"message_number\": 0}", "attributes": {"question_uuid": "7bc572dc-ab8b-4aed-a132-b0b509caceb3", "forward_logs": "1", "allow_save_diagnostics_data_on_crash": "1", "octue_sdk_version": "0.50.0"}}} +{"parent_sdk_version": "0.50.1", "question": {"data": "{\"input_values\": {\"height\": 4, \"width\": 72}, \"input_manifest\": {\"id\": \"64fd48b8-8c81-4c7b-9cd3-466b8e612b60\", \"name\": null, \"datasets\": {\"my_dataset\": \"/var/folders/sk/hf5fbp616c77tsys9lz55qn40000gp/T/tmpya5m1ib5\"}}, \"children\": null, \"message_number\": 0}", "attributes": {"question_uuid": "d54e9568-c88f-4233-a217-636bf3a77f74", "forward_logs": "1", "allow_save_diagnostics_data_on_crash": "1", "octue_sdk_version": "0.50.1"}}} +{"parent_sdk_version": "0.51.0", "question": {"data": "{\"kind\": \"question\", \"input_values\": {\"height\": 4, \"width\": 72}, \"input_manifest\": {\"id\": \"3bf3b178-3cf1-49aa-a1d9-89cd8ec05b1a\", \"name\": null, \"datasets\": {\"my_dataset\": \"/var/folders/sk/hf5fbp616c77tsys9lz55qn40000gp/T/tmppu85nw5c\"}}}", "attributes": {"question_uuid": "6f7f6e1c-7632-4b4d-b91d-6f58dcb43c40", "sender_type": "PARENT", "forward_logs": "1", "save_diagnostics": "SAVE_DIAGNOSTICS_ON_CRASH", "version": "0.51.0", "message_number": "0"}}} +{"parent_sdk_version": "0.52.0", "question": {"data": "{\"kind\": \"question\", \"input_values\": {\"height\": 4, \"width\": 72}, \"input_manifest\": {\"id\": \"6be875b3-33d8-4b00-b7ea-553f8f69bce5\", \"name\": null, \"datasets\": {\"my_dataset\": \"/var/folders/sk/hf5fbp616c77tsys9lz55qn40000gp/T/tmphypwu9uh\"}}}", "attributes": {"question_uuid": "cd0a78be-fda2-4730-bdba-ba6b04e4787f", "sender_type": "PARENT", "forward_logs": "1", "save_diagnostics": "SAVE_DIAGNOSTICS_ON_CRASH", "version": "0.52.0", "message_number": "0"}}} diff --git a/octue/metadata/version_compatibilities.json b/octue/metadata/version_compatibilities.json index 302109633..bc36afd3e 100644 --- a/octue/metadata/version_compatibilities.json +++ b/octue/metadata/version_compatibilities.json @@ -42,7 +42,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.34.1": { "0.40.1": true, @@ -87,7 +88,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.34.0": { "0.40.1": true, @@ -132,7 +134,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.33.0": { "0.40.1": true, @@ -177,7 +180,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.32.0": { "0.40.1": true, @@ -222,7 +226,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.31.0": { "0.40.1": true, @@ -267,7 +272,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.30.0": { "0.40.1": true, @@ -312,7 +318,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.36.0": { "0.40.1": true, @@ -357,7 +364,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.37.0": { "0.40.1": true, @@ -402,7 +410,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.38.0": { "0.40.1": true, @@ -447,7 +456,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.38.1": { "0.40.1": true, @@ -492,7 +502,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.39.0": { "0.40.1": true, @@ -537,7 +548,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.40.0": { "0.40.1": true, @@ -582,7 +594,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.40.1": { "0.40.1": true, @@ -627,7 +640,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.40.2": { "0.41.0": true, @@ -672,7 +686,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.41.0": { "0.41.0": true, @@ -717,7 +732,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.41.1": { "0.41.1": true, @@ -762,7 +778,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.42.0": { "0.42.0": true, @@ -807,7 +824,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.42.1": { "0.43.2": true, @@ -852,7 +870,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.0": { "0.43.2": true, @@ -897,7 +916,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.1": { "0.43.2": true, @@ -942,7 +962,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.2": { "0.43.2": true, @@ -987,7 +1008,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.3": { "0.43.3": true, @@ -1032,7 +1054,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.4": { "0.43.4": true, @@ -1077,7 +1100,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.5": { "0.43.5": true, @@ -1122,7 +1146,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.6": { "0.43.6": true, @@ -1167,7 +1192,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.43.7": { "0.43.7": true, @@ -1212,7 +1238,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.44.0": { "0.44.0": true, @@ -1257,7 +1284,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.45.0": { "0.45.0": true, @@ -1302,7 +1330,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.46.0": { "0.46.0": true, @@ -1347,7 +1376,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.46.1": { "0.46.1": true, @@ -1392,7 +1422,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.46.2": { "0.46.2": true, @@ -1437,7 +1468,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.46.3": { "0.46.3": true, @@ -1482,7 +1514,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.47.0": { "0.47.0": true, @@ -1527,7 +1560,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.47.1": { "0.47.1": true, @@ -1572,7 +1606,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.47.2": { "0.47.2": true, @@ -1617,7 +1652,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.48.0": { "0.48.0": true, @@ -1662,7 +1698,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.49.0": { "0.49.1": true, @@ -1707,7 +1744,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.49.1": { "0.49.1": true, @@ -1752,7 +1790,8 @@ "0.49.2": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.49.2": { "0.49.2": true, @@ -1797,7 +1836,8 @@ "0.30.0": true, "0.50.0": true, "0.50.1": true, - "0.51.0": false + "0.51.0": false, + "0.52.0": false }, "0.50.0": { "0.50.0": true, @@ -1842,7 +1882,8 @@ "0.33.0": true, "0.32.0": true, "0.31.0": true, - "0.30.0": true + "0.30.0": true, + "0.52.0": false }, "0.50.1": { "0.51.0": false, @@ -1887,7 +1928,8 @@ "0.33.0": true, "0.32.0": true, "0.31.0": true, - "0.30.0": true + "0.30.0": true, + "0.52.0": false }, "0.51.0": { "0.51.0": true, @@ -1932,6 +1974,53 @@ "0.33.0": false, "0.32.0": false, "0.31.0": false, - "0.30.0": false + "0.30.0": false, + "0.52.0": true + }, + "0.52.0": { + "0.51.0": true, + "0.50.1": false, + "0.50.0": false, + "0.49.2": false, + "0.49.1": false, + "0.49.0": false, + "0.48.0": false, + "0.47.2": false, + "0.47.1": false, + "0.47.0": false, + "0.46.3": false, + "0.46.2": false, + "0.46.1": false, + "0.46.0": false, + "0.45.0": false, + "0.44.0": false, + "0.43.7": false, + "0.43.6": false, + "0.43.5": false, + "0.43.4": false, + "0.43.3": false, + "0.43.2": false, + "0.43.1": false, + "0.43.0": false, + "0.42.1": false, + "0.42.0": false, + "0.41.1": false, + "0.41.0": false, + "0.40.2": false, + "0.40.1": false, + "0.40.0": false, + "0.39.0": false, + "0.38.1": false, + "0.38.0": false, + "0.37.0": false, + "0.36.0": false, + "0.35.0": false, + "0.34.1": false, + "0.34.0": false, + "0.33.0": false, + "0.32.0": false, + "0.31.0": false, + "0.30.0": false, + "0.52.0": true } } From 13c4190633f4dc2a665b14a404d2f9259db6ade8 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Mon, 5 Feb 2024 15:45:36 +0000 Subject: [PATCH 40/40] DEP: Update lock file --- poetry.lock | 515 +++++++++++++++++++++++++++------------------------- 1 file changed, 269 insertions(+), 246 deletions(-) diff --git a/poetry.lock b/poetry.lock index adc30a35e..3185461e7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -34,13 +34,13 @@ limiter = ["cachecontrol[filecache] (>=0.12.6)", "lockfile (>=0.12.2)"] [[package]] name = "apeye-core" -version = "1.1.4" +version = "1.1.5" description = "Core (offline) functionality for the apeye library." optional = false python-versions = ">=3.6.1" files = [ - {file = "apeye_core-1.1.4-py3-none-any.whl", hash = "sha256:084bc696448d3ac428fece41c1f2eb08fa9d9ce1d1b2f4d43187e3def4528a60"}, - {file = "apeye_core-1.1.4.tar.gz", hash = "sha256:72bb89fed3baa647cb81aa28e1d851787edcbf9573853b5d2b5f87c02f50eaf5"}, + {file = "apeye_core-1.1.5-py3-none-any.whl", hash = "sha256:dc27a93f8c9e246b3b238c5ea51edf6115ab2618ef029b9f2d9a190ec8228fbf"}, + {file = "apeye_core-1.1.5.tar.gz", hash = "sha256:5de72ed3d00cc9b20fea55e54b7ab8f5ef8500eb33a5368bc162a5585e238a55"}, ] [package.dependencies] @@ -60,13 +60,13 @@ files = [ [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.dependencies] @@ -74,20 +74,21 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "autodocsumm" -version = "0.2.11" +version = "0.2.12" description = "Extended sphinx autodoc including automatic autosummaries" optional = false python-versions = ">=3.7" files = [ - {file = "autodocsumm-0.2.11-py3-none-any.whl", hash = "sha256:f1d0a623bf1ad64d979a9e23fd360d1fb1b8f869beaf3197f711552cddc174e2"}, - {file = "autodocsumm-0.2.11.tar.gz", hash = "sha256:183212bd9e9f3b58a96bb21b7958ee4e06224107aa45b2fd894b61b83581b9a9"}, + {file = "autodocsumm-0.2.12-py3-none-any.whl", hash = "sha256:b842b53c686c07a4f174721ca4e729b027367703dbf42e2508863a3c6d6c049c"}, + {file = "autodocsumm-0.2.12.tar.gz", hash = "sha256:848fe8c38df433c6635489499b969cb47cc389ed3d7b6e75c8ccbc94d4b3bf9e"}, ] [package.dependencies] @@ -95,18 +96,17 @@ Sphinx = ">=2.2,<8.0" [[package]] name = "babel" -version = "2.13.1" +version = "2.14.0" description = "Internationalization utilities" optional = false python-versions = ">=3.7" files = [ - {file = "Babel-2.13.1-py3-none-any.whl", hash = "sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed"}, - {file = "Babel-2.13.1.tar.gz", hash = "sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900"}, + {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, + {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, ] [package.dependencies] pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} -setuptools = {version = "*", markers = "python_version >= \"3.12\""} [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] @@ -141,19 +141,22 @@ tzdata = ["tzdata"] [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] @@ -206,22 +209,22 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "cachecontrol" -version = "0.13.1" +version = "0.14.0" description = "httplib2 caching for requests" optional = false python-versions = ">=3.7" files = [ - {file = "cachecontrol-0.13.1-py3-none-any.whl", hash = "sha256:95dedbec849f46dda3137866dc28b9d133fc9af55f5b805ab1291833e4457aa4"}, - {file = "cachecontrol-0.13.1.tar.gz", hash = "sha256:f012366b79d2243a6118309ce73151bf52a38d4a5dac8ea57f09bd29087e506b"}, + {file = "cachecontrol-0.14.0-py3-none-any.whl", hash = "sha256:f5bf3f0620c38db2e5122c0726bdebb0d16869de966ea6a2befe92470b740ea0"}, + {file = "cachecontrol-0.14.0.tar.gz", hash = "sha256:7db1195b41c81f8274a7bbd97c956f44e8348265a1bc7641c37dfebc39f0c938"}, ] [package.dependencies] filelock = {version = ">=3.8.0", optional = true, markers = "extra == \"filecache\""} -msgpack = ">=0.5.2" +msgpack = ">=0.5.2,<2.0.0" requests = ">=2.16.0" [package.extras] -dev = ["CacheControl[filecache,redis]", "black", "build", "cherrypy", "mypy", "pytest", "pytest-cov", "sphinx", "tox", "types-redis", "types-requests"] +dev = ["CacheControl[filecache,redis]", "black", "build", "cherrypy", "furo", "mypy", "pytest", "pytest-cov", "sphinx", "sphinx-copybutton", "tox", "types-redis", "types-requests"] filecache = ["filelock (>=3.8.0)"] redis = ["redis (>=2.10.5)"] @@ -238,13 +241,13 @@ files = [ [[package]] name = "certifi" -version = "2023.7.22" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -500,13 +503,13 @@ langdetect = ["langdetect"] [[package]] name = "dict2css" -version = "0.3.0" +version = "0.3.0.post1" description = "A μ-library for constructing cascading style sheets from Python dictionaries." optional = false python-versions = ">=3.6" files = [ - {file = "dict2css-0.3.0-py3-none-any.whl", hash = "sha256:ef934ce73a225fdd5f811b484fe9e2dd768f7ef14a89fc8f4eb5672597131d00"}, - {file = "dict2css-0.3.0.tar.gz", hash = "sha256:1e8b1bf580dca2083198f88a60ec88c878a8829d760dfe45483ef80fe2905117"}, + {file = "dict2css-0.3.0.post1-py3-none-any.whl", hash = "sha256:f006a6b774c3e31869015122ae82c491fd25e7de4a75607a62aa3e798f837e0d"}, + {file = "dict2css-0.3.0.post1.tar.gz", hash = "sha256:89c544c21c4ca7472c3fffb9d37d3d926f606329afdb751dc1de67a411b70719"}, ] [package.dependencies] @@ -515,13 +518,13 @@ domdf-python-tools = ">=2.2.0" [[package]] name = "distlib" -version = "0.3.7" +version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, - {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] [[package]] @@ -537,13 +540,13 @@ files = [ [[package]] name = "domdf-python-tools" -version = "3.7.0" +version = "3.8.0.post2" description = "Helpful functions for Python 🐍 🛠️" optional = false python-versions = ">=3.6" files = [ - {file = "domdf_python_tools-3.7.0-py3-none-any.whl", hash = "sha256:7b4d1c3bdb7402b872d43953824bf921ae2e52f893adbe5c0052a21a6efa2fe4"}, - {file = "domdf_python_tools-3.7.0.tar.gz", hash = "sha256:df1af9a91649af0fb2a4e7b3a4b0a0936e4f78389dd7280dd6fd2f53a339ca71"}, + {file = "domdf_python_tools-3.8.0.post2-py3-none-any.whl", hash = "sha256:ad2c763c8d00850a7fa92ad95e9891a1918281ea25322c4dbb1734fd32f905dd"}, + {file = "domdf_python_tools-3.8.0.post2.tar.gz", hash = "sha256:a1fd255ea29f767b08de462d2da39d360262304389227d980bc307ee8aa3366a"}, ] [package.dependencies] @@ -557,13 +560,13 @@ dates = ["pytz (>=2019.1)"] [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -659,25 +662,25 @@ google-crc32c = "1.3.0" [[package]] name = "google-api-core" -version = "2.14.0" +version = "2.16.2" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.14.0.tar.gz", hash = "sha256:5368a4502b793d9bbf812a5912e13e4e69f9bd87f6efb508460c43f5bbd1ce41"}, - {file = "google_api_core-2.14.0-py3-none-any.whl", hash = "sha256:de2fb50ed34d47ddbb2bd2dcf680ee8fead46279f4ed6b16de362aca23a18952"}, + {file = "google-api-core-2.16.2.tar.gz", hash = "sha256:032d37b45d1d6bdaf68fb11ff621e2593263a239fa9246e2e94325f9c47876d2"}, + {file = "google_api_core-2.16.2-py3-none-any.whl", hash = "sha256:449ca0e3f14c179b4165b664256066c7861610f70b6ffe54bb01a04e9b466929"}, ] [package.dependencies] google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = [ - {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, + {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, ] grpcio-status = [ - {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, + {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, ] protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" @@ -689,13 +692,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.23.4" +version = "2.27.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.23.4.tar.gz", hash = "sha256:79905d6b1652187def79d491d6e23d0cbb3a21d3c7ba0dbaa9c8a01906b13ff3"}, - {file = "google_auth-2.23.4-py2.py3-none-any.whl", hash = "sha256:d4bbc92fe4b8bfd2f3e8d88e5ba7085935da208ee38a134fc280e7ce682a05f2"}, + {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, + {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, ] [package.dependencies] @@ -712,31 +715,32 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-cloud-core" -version = "2.3.3" +version = "2.4.1" description = "Google Cloud API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-core-2.3.3.tar.gz", hash = "sha256:37b80273c8d7eee1ae816b3a20ae43585ea50506cb0e60f3cf5be5f87f1373cb"}, - {file = "google_cloud_core-2.3.3-py2.py3-none-any.whl", hash = "sha256:fbd11cad3e98a7e5b0343dc07cb1039a5ffd7a5bb96e1f1e27cee4bda4a90863"}, + {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, + {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, ] [package.dependencies] google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" google-auth = ">=1.25.0,<3.0dev" +importlib-metadata = {version = ">1.0.0", markers = "python_version < \"3.8\""} [package.extras] -grpc = ["grpcio (>=1.38.0,<2.0dev)"] +grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] name = "google-cloud-pubsub" -version = "2.18.4" +version = "2.19.1" description = "Google Cloud Pub/Sub API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-pubsub-2.18.4.tar.gz", hash = "sha256:32eb61fd4c1dc6c842f594d69d9afa80544e3b327aa640a164eb6fb0201eaf2d"}, - {file = "google_cloud_pubsub-2.18.4-py2.py3-none-any.whl", hash = "sha256:f32144ad9ed32331a80a2f8379a3ca7526bbc01e7bd76de2e8ab52e492d21f50"}, + {file = "google-cloud-pubsub-2.19.1.tar.gz", hash = "sha256:c10d95ebaf903f923b14aa8ec5b7c80916138edf299c65a1c1a9431fd5665d25"}, + {file = "google_cloud_pubsub-2.19.1-py2.py3-none-any.whl", hash = "sha256:602eacbe5735f38d3ae384ece8f235db0594de78ad718a35fcb948dc4964612c"}, ] [package.dependencies] @@ -745,8 +749,8 @@ grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" grpcio = ">=1.51.3,<2.0dev" grpcio-status = ">=1.33.2" proto-plus = [ - {version = ">=1.22.2,<2.0.0dev", markers = "python_version >= \"3.11\""}, {version = ">=1.22.0,<2.0.0dev", markers = "python_version < \"3.11\""}, + {version = ">=1.22.2,<2.0.0dev", markers = "python_version >= \"3.11\""}, ] protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" @@ -755,33 +759,30 @@ libcst = ["libcst (>=0.3.10)"] [[package]] name = "google-cloud-secret-manager" -version = "2.16.4" +version = "2.18.0" description = "Google Cloud Secret Manager API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-secret-manager-2.16.4.tar.gz", hash = "sha256:371dc72f9145af323e8a813c8e50380e6ac4bd6a5dbcd42dcf3162d8f37e5080"}, - {file = "google_cloud_secret_manager-2.16.4-py2.py3-none-any.whl", hash = "sha256:5031c45dd84dc584d91ee0baae2bbd5df6710efe0c42719ee370a3ab62aaf618"}, + {file = "google-cloud-secret-manager-2.18.0.tar.gz", hash = "sha256:4e499bd33ff7aeff271bd67487e21d5404297a86dc4873ee861d637b01b30b4e"}, + {file = "google_cloud_secret_manager-2.18.0-py2.py3-none-any.whl", hash = "sha256:06ce001648a75fc7e992e3e658772b10a6ebc738a49463204c44409137ad5890"}, ] [package.dependencies] google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = [ - {version = ">=1.22.2,<2.0.0dev", markers = "python_version >= \"3.11\""}, - {version = ">=1.22.0,<2.0.0dev", markers = "python_version < \"3.11\""}, -] +proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" [[package]] name = "google-cloud-storage" -version = "2.13.0" +version = "2.14.0" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-2.13.0.tar.gz", hash = "sha256:f62dc4c7b6cd4360d072e3deb28035fbdad491ac3d9b0b1815a12daea10f37c7"}, - {file = "google_cloud_storage-2.13.0-py2.py3-none-any.whl", hash = "sha256:ab0bf2e1780a1b74cf17fccb13788070b729f50c252f0c94ada2aae0ca95437d"}, + {file = "google-cloud-storage-2.14.0.tar.gz", hash = "sha256:2d23fcf59b55e7b45336729c148bb1c464468c69d5efbaee30f7201dd90eb97e"}, + {file = "google_cloud_storage-2.14.0-py2.py3-none-any.whl", hash = "sha256:8641243bbf2a2042c16a6399551fbb13f062cbc9a2de38d6c0bb5426962e9dbd"}, ] [package.dependencies] @@ -852,13 +853,13 @@ testing = ["pytest"] [[package]] name = "google-resumable-media" -version = "2.6.0" +version = "2.7.0" description = "Utilities for Google Media Downloads and Resumable Uploads" optional = false python-versions = ">= 3.7" files = [ - {file = "google-resumable-media-2.6.0.tar.gz", hash = "sha256:972852f6c65f933e15a4a210c2b96930763b47197cdf4aa5f5bea435efb626e7"}, - {file = "google_resumable_media-2.6.0-py2.py3-none-any.whl", hash = "sha256:fc03d344381970f79eebb632a3c18bb1828593a2dc5572b5f90115ef7d11e81b"}, + {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, + {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, ] [package.dependencies] @@ -870,13 +871,13 @@ requests = ["requests (>=2.18.0,<3.0.0dev)"] [[package]] name = "googleapis-common-protos" -version = "1.61.0" +version = "1.62.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.61.0.tar.gz", hash = "sha256:8a64866a97f6304a7179873a465d6eee97b7a24ec6cfd78e0f575e96b821240b"}, - {file = "googleapis_common_protos-1.61.0-py2.py3-none-any.whl", hash = "sha256:22f1915393bb3245343f6efe87f6fe868532efc12aa26b391b15132e1279f1c0"}, + {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, + {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, ] [package.dependencies] @@ -888,13 +889,13 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "grpc-google-iam-v1" -version = "0.12.7" +version = "0.13.0" description = "IAM API client library" optional = false python-versions = ">=3.7" files = [ - {file = "grpc-google-iam-v1-0.12.7.tar.gz", hash = "sha256:009197a7f1eaaa22149c96e5e054ac5934ba7241974e92663d8d3528a21203d1"}, - {file = "grpc_google_iam_v1-0.12.7-py2.py3-none-any.whl", hash = "sha256:834da89f4c4a2abbe842a793ed20fc6d9a77011ef2626755b1b89116fb9596d7"}, + {file = "grpc-google-iam-v1-0.13.0.tar.gz", hash = "sha256:fad318608b9e093258fbf12529180f400d1c44453698a33509cc6ecf005b294e"}, + {file = "grpc_google_iam_v1-0.13.0-py2.py3-none-any.whl", hash = "sha256:53902e2af7de8df8c1bd91373d9be55b0743ec267a7428ea638db3775becae89"}, ] [package.dependencies] @@ -904,84 +905,84 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4 [[package]] name = "grpcio" -version = "1.59.2" +version = "1.60.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.59.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:d2fa68a96a30dd240be80bbad838a0ac81a61770611ff7952b889485970c4c71"}, - {file = "grpcio-1.59.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:cf0dead5a2c5a3347af2cfec7131d4f2a2e03c934af28989c9078f8241a491fa"}, - {file = "grpcio-1.59.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:e420ced29b5904cdf9ee5545e23f9406189d8acb6750916c2db4793dada065c6"}, - {file = "grpcio-1.59.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b230028a008ae1d0f430acb227d323ff8a619017415cf334c38b457f814119f"}, - {file = "grpcio-1.59.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a4a3833c0e067f3558538727235cd8a49709bff1003200bbdefa2f09334e4b1"}, - {file = "grpcio-1.59.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6b25ed37c27e652db01be341af93fbcea03d296c024d8a0e680017a268eb85dd"}, - {file = "grpcio-1.59.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73abb8584b0cf74d37f5ef61c10722adc7275502ab71789a8fe3cb7ef04cf6e2"}, - {file = "grpcio-1.59.2-cp310-cp310-win32.whl", hash = "sha256:d6f70406695e3220f09cd7a2f879333279d91aa4a8a1d34303b56d61a8180137"}, - {file = "grpcio-1.59.2-cp310-cp310-win_amd64.whl", hash = "sha256:3c61d641d4f409c5ae46bfdd89ea42ce5ea233dcf69e74ce9ba32b503c727e29"}, - {file = "grpcio-1.59.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:3059668df17627f0e0fa680e9ef8c995c946c792612e9518f5cc1503be14e90b"}, - {file = "grpcio-1.59.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:72ca2399097c0b758198f2ff30f7178d680de8a5cfcf3d9b73a63cf87455532e"}, - {file = "grpcio-1.59.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:c978f864b35f2261e0819f5cd88b9830b04dc51bcf055aac3c601e525a10d2ba"}, - {file = "grpcio-1.59.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9411e24328a2302e279e70cae6e479f1fddde79629fcb14e03e6d94b3956eabf"}, - {file = "grpcio-1.59.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb7e0fe6ad73b7f06d7e2b689c19a71cf5cc48f0c2bf8608469e51ffe0bd2867"}, - {file = "grpcio-1.59.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c2504eed520958a5b77cc99458297cb7906308cb92327f35fb7fbbad4e9b2188"}, - {file = "grpcio-1.59.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2171c39f355ba5b551c5d5928d65aa6c69807fae195b86ef4a7d125bcdb860a9"}, - {file = "grpcio-1.59.2-cp311-cp311-win32.whl", hash = "sha256:d2794f0e68b3085d99b4f6ff9c089f6fdd02b32b9d3efdfbb55beac1bf22d516"}, - {file = "grpcio-1.59.2-cp311-cp311-win_amd64.whl", hash = "sha256:2067274c88bc6de89c278a672a652b4247d088811ece781a4858b09bdf8448e3"}, - {file = "grpcio-1.59.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:535561990e075fa6bd4b16c4c3c1096b9581b7bb35d96fac4650f1181e428268"}, - {file = "grpcio-1.59.2-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a213acfbf186b9f35803b52e4ca9addb153fc0b67f82a48f961be7000ecf6721"}, - {file = "grpcio-1.59.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:6959fb07e8351e20501ffb8cc4074c39a0b7ef123e1c850a7f8f3afdc3a3da01"}, - {file = "grpcio-1.59.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e82c5cf1495244adf5252f925ac5932e5fd288b3e5ab6b70bec5593074b7236c"}, - {file = "grpcio-1.59.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023088764012411affe7db183d1ada3ad9daf2e23ddc719ff46d7061de661340"}, - {file = "grpcio-1.59.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:da2d94c15f88cd40d7e67f7919d4f60110d2b9d5b1e08cf354c2be773ab13479"}, - {file = "grpcio-1.59.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6009386a2df66159f64ac9f20425ae25229b29b9dd0e1d3dd60043f037e2ad7e"}, - {file = "grpcio-1.59.2-cp312-cp312-win32.whl", hash = "sha256:75c6ecb70e809cf1504465174343113f51f24bc61e22a80ae1c859f3f7034c6d"}, - {file = "grpcio-1.59.2-cp312-cp312-win_amd64.whl", hash = "sha256:cbe946b3e6e60a7b4618f091e62a029cb082b109a9d6b53962dd305087c6e4fd"}, - {file = "grpcio-1.59.2-cp37-cp37m-linux_armv7l.whl", hash = "sha256:f8753a6c88d1d0ba64302309eecf20f70d2770f65ca02d83c2452279085bfcd3"}, - {file = "grpcio-1.59.2-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:f1ef0d39bc1feb420caf549b3c657c871cad4ebbcf0580c4d03816b0590de0cf"}, - {file = "grpcio-1.59.2-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:4c93f4abbb54321ee6471e04a00139c80c754eda51064187963ddf98f5cf36a4"}, - {file = "grpcio-1.59.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08d77e682f2bf730a4961eea330e56d2f423c6a9b91ca222e5b1eb24a357b19f"}, - {file = "grpcio-1.59.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ff16d68bf453275466a9a46739061a63584d92f18a0f5b33d19fc97eb69867c"}, - {file = "grpcio-1.59.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4abb717e320e74959517dc8e84a9f48fbe90e9abe19c248541e9418b1ce60acd"}, - {file = "grpcio-1.59.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:36f53c2b3449c015880e7d55a89c992c357f176327b0d2873cdaaf9628a37c69"}, - {file = "grpcio-1.59.2-cp37-cp37m-win_amd64.whl", hash = "sha256:cc3e4cd087f07758b16bef8f31d88dbb1b5da5671d2f03685ab52dece3d7a16e"}, - {file = "grpcio-1.59.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:27f879ae604a7fcf371e59fba6f3ff4635a4c2a64768bd83ff0cac503142fef4"}, - {file = "grpcio-1.59.2-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:7cf05053242f61ba94014dd3a986e11a083400a32664058f80bf4cf817c0b3a1"}, - {file = "grpcio-1.59.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:e1727c1c0e394096bb9af185c6923e8ea55a5095b8af44f06903bcc0e06800a2"}, - {file = "grpcio-1.59.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d573e70a6fe77555fb6143c12d3a7d3fa306632a3034b4e7c59ca09721546f8"}, - {file = "grpcio-1.59.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31176aa88f36020055ace9adff2405a33c8bdbfa72a9c4980e25d91b2f196873"}, - {file = "grpcio-1.59.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11168ef43e4a43ff1b1a65859f3e0ef1a173e277349e7fb16923ff108160a8cd"}, - {file = "grpcio-1.59.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:53c9aa5ddd6857c0a1cd0287225a2a25873a8e09727c2e95c4aebb1be83a766a"}, - {file = "grpcio-1.59.2-cp38-cp38-win32.whl", hash = "sha256:3b4368b33908f683a363f376dfb747d40af3463a6e5044afee07cf9436addf96"}, - {file = "grpcio-1.59.2-cp38-cp38-win_amd64.whl", hash = "sha256:0a754aff9e3af63bdc4c75c234b86b9d14e14a28a30c4e324aed1a9b873d755f"}, - {file = "grpcio-1.59.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:1f9524d1d701e399462d2c90ba7c193e49d1711cf429c0d3d97c966856e03d00"}, - {file = "grpcio-1.59.2-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:f93dbf58f03146164048be5426ffde298b237a5e059144847e4940f5b80172c3"}, - {file = "grpcio-1.59.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:6da6dea3a1bacf99b3c2187e296db9a83029ed9c38fd4c52b7c9b7326d13c828"}, - {file = "grpcio-1.59.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5f09cffa619adfb44799fa4a81c2a1ad77c887187613fb0a8f201ab38d89ba1"}, - {file = "grpcio-1.59.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c35aa9657f5d5116d23b934568e0956bd50c615127810fffe3ac356a914c176a"}, - {file = "grpcio-1.59.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:74100fecaec8a535e380cf5f2fb556ff84957d481c13e54051c52e5baac70541"}, - {file = "grpcio-1.59.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:128e20f57c5f27cb0157e73756d1586b83c1b513ebecc83ea0ac37e4b0e4e758"}, - {file = "grpcio-1.59.2-cp39-cp39-win32.whl", hash = "sha256:686e975a5d16602dc0982c7c703948d17184bd1397e16c8ee03511ecb8c4cdda"}, - {file = "grpcio-1.59.2-cp39-cp39-win_amd64.whl", hash = "sha256:242adc47725b9a499ee77c6a2e36688fa6c96484611f33b1be4c57ab075a92dd"}, - {file = "grpcio-1.59.2.tar.gz", hash = "sha256:d8f9cd4ad1be90b0cf350a2f04a38a36e44a026cac1e036ac593dc48efe91d52"}, + {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, + {file = "grpcio-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb"}, + {file = "grpcio-1.60.1-cp310-cp310-win32.whl", hash = "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1"}, + {file = "grpcio-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177"}, + {file = "grpcio-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303"}, + {file = "grpcio-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce"}, + {file = "grpcio-1.60.1-cp311-cp311-win32.whl", hash = "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd"}, + {file = "grpcio-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c"}, + {file = "grpcio-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9"}, + {file = "grpcio-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05"}, + {file = "grpcio-1.60.1-cp312-cp312-win32.whl", hash = "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21"}, + {file = "grpcio-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f"}, + {file = "grpcio-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594"}, + {file = "grpcio-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e"}, + {file = "grpcio-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de"}, + {file = "grpcio-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549"}, + {file = "grpcio-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a"}, + {file = "grpcio-1.60.1-cp38-cp38-win32.whl", hash = "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929"}, + {file = "grpcio-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872"}, + {file = "grpcio-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8"}, + {file = "grpcio-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6"}, + {file = "grpcio-1.60.1-cp39-cp39-win32.whl", hash = "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804"}, + {file = "grpcio-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904"}, + {file = "grpcio-1.60.1.tar.gz", hash = "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.59.2)"] +protobuf = ["grpcio-tools (>=1.60.1)"] [[package]] name = "grpcio-status" -version = "1.59.2" +version = "1.60.1" description = "Status proto mapping for gRPC" optional = false python-versions = ">=3.6" files = [ - {file = "grpcio-status-1.59.2.tar.gz", hash = "sha256:a2c2b146e66b73ba80d021ab34fce5db4dd9be67ca4566cda40d36b185ce54f4"}, - {file = "grpcio_status-1.59.2-py3-none-any.whl", hash = "sha256:24bdf3b3b83b9112f43bd0626f82510d12cc1d919a45028ac20eb6919218e508"}, + {file = "grpcio-status-1.60.1.tar.gz", hash = "sha256:61b5aab8989498e8aa142c20b88829ea5d90d18c18c853b9f9e6d407d37bf8b4"}, + {file = "grpcio_status-1.60.1-py3-none-any.whl", hash = "sha256:3034fdb239185b6e0f3169d08c268c4507481e4b8a434c21311a03d9eb5889a0"}, ] [package.dependencies] googleapis-common-protos = ">=1.5.5" -grpcio = ">=1.59.2" +grpcio = ">=1.60.1" protobuf = ">=4.21.6" [[package]] @@ -1078,13 +1079,13 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -1177,13 +1178,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -1227,61 +1228,71 @@ files = [ [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] @@ -1491,10 +1502,10 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.17.3", markers = "(platform_machine != \"aarch64\" and platform_machine != \"arm64\") and python_version < \"3.10\""}, {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""}, {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, ] python-dateutil = ">=2.7.3" pytz = ">=2017.3" @@ -1551,13 +1562,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "2.20.0" +version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.7" files = [ - {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, - {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, + {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, + {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, ] [package.dependencies] @@ -1566,18 +1577,17 @@ identify = ">=1.0.0" importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} nodeenv = ">=0.11.1" pyyaml = ">=5.1" -toml = "*" -virtualenv = ">=20.0.8" +virtualenv = ">=20.10.0" [[package]] name = "proto-plus" -version = "1.22.3" +version = "1.23.0" description = "Beautiful, Pythonic protocol buffers." optional = false python-versions = ">=3.6" files = [ - {file = "proto-plus-1.22.3.tar.gz", hash = "sha256:fdcd09713cbd42480740d2fe29c990f7fbd885a67efc328aa8be6ee3e9f76a6b"}, - {file = "proto_plus-1.22.3-py3-none-any.whl", hash = "sha256:a49cd903bc0b6ab41f76bf65510439d56ca76f868adf0274e738bfdd096894df"}, + {file = "proto-plus-1.23.0.tar.gz", hash = "sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2"}, + {file = "proto_plus-1.23.0-py3-none-any.whl", hash = "sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c"}, ] [package.dependencies] @@ -1621,13 +1631,13 @@ files = [ [[package]] name = "pyasn1" -version = "0.5.0" +version = "0.5.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "pyasn1-0.5.0-py2.py3-none-any.whl", hash = "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57"}, - {file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"}, + {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, + {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, ] [[package]] @@ -1668,17 +1678,18 @@ files = [ [[package]] name = "pygments" -version = "2.16.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyrsistent" @@ -1718,13 +1729,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -1769,13 +1780,13 @@ cli = ["click (>=5.0)"] [[package]] name = "pytz" -version = "2023.3.post1" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -1790,6 +1801,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1797,8 +1809,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1815,6 +1834,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1822,6 +1842,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1972,37 +1993,51 @@ python-versions = ">=3.6" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, @@ -2112,13 +2147,13 @@ type-comments = ["typed-ast (>=1.4.0)"] [[package]] name = "sphinx-jinja2-compat" -version = "0.2.0" +version = "0.2.0.post1" description = "Patches Jinja2 v3 to restore compatibility with earlier Sphinx versions." optional = false python-versions = ">=3.6" files = [ - {file = "sphinx_jinja2_compat-0.2.0-py3-none-any.whl", hash = "sha256:a5f3112d6873991c2cf28e37287163a0485d9c0812863b8aa4df7182722501fb"}, - {file = "sphinx_jinja2_compat-0.2.0.tar.gz", hash = "sha256:c41346d859653e202b623f4236da8936243ed734abf5984adc3bef59d6f9a946"}, + {file = "sphinx_jinja2_compat-0.2.0.post1-py3-none-any.whl", hash = "sha256:f9d329174bdde8db19dc12c62528367196eb2f6b46c91754eca604acd0c0f6ad"}, + {file = "sphinx_jinja2_compat-0.2.0.post1.tar.gz", hash = "sha256:974289a12a9f402108dead621e9c15f7004e945d5cfcaea8d6419e94d3fa95a3"}, ] [package.dependencies] @@ -2340,17 +2375,6 @@ files = [ [package.extras] widechars = ["wcwidth"] -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] - [[package]] name = "tomli" version = "2.0.1" @@ -2481,13 +2505,13 @@ typing-extensions = ">=3.7.4" [[package]] name = "tzdata" -version = "2023.3" +version = "2023.4" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, + {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, ] [[package]] @@ -2527,25 +2551,24 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.4.7" +version = "20.25.0" description = "Virtual Python Environment builder" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = ">=3.7" files = [ - {file = "virtualenv-20.4.7-py2.py3-none-any.whl", hash = "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"}, - {file = "virtualenv-20.4.7.tar.gz", hash = "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] [package.dependencies] -appdirs = ">=1.4.3,<2" -distlib = ">=0.3.1,<1" -filelock = ">=3.0.0,<4" -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} -six = ">=1.9.0,<2" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""} +platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] -testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "packaging (>=20.0)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "xonsh (>=0.9.16)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "webencodings"