Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broadcast template fix #1592

Conversation

maheshsattala
Copy link
Contributor

@maheshsattala maheshsattala commented Nov 7, 2024

Broadcast template issue handled and added test cases related to the same.

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced error handling in message broadcasting, particularly for template retrieval.
    • Introduced a method to validate retry limits for broadcast events.
    • Improved flexibility in updating broadcast logs with additional parameters.
  • Bug Fixes

    • Improved logging for message broadcasting attempts, including detailed error information.
    • Enhanced exception handling in the template listing process.
  • Tests

    • Added new test cases to ensure robust handling of exceptions during message broadcasting and template management.

Copy link

coderabbitai bot commented Nov 7, 2024

Walkthrough

The pull request introduces several changes across multiple files, primarily focusing on enhancing the functionality and error handling of the MessageBroadcastEvent and WhatsappBroadcast classes. Key modifications include the introduction of a new method for validating retry limits, adjustments to exception handling during template retrieval, and improvements to logging mechanisms. Additionally, new test cases have been added to ensure comprehensive coverage of the updated functionalities, particularly in scenarios involving error handling and template management.

Changes

File Path Change Summary
kairon/events/definitions/message_broadcast.py - Modified execute method to change initial status and adjust exception handling.
- Added validate_retry_broadcast method to check retry limits.
kairon/shared/channels/broadcast/whatsapp.py - Updated __get_template method to handle exceptions and return templates.
- Enhanced error handling in __send_using_pyscript and __send_using_configuration methods.
kairon/shared/chat/broadcast/processor.py - Updated update_broadcast_logs_with_template method to accept **kwargs for flexibility.
- Streamlined error handling in delete_task and clarified logic in add_event_log.
tests/unit_test/events/events_test.py - Added tests for exception handling and logging in MessageBroadcastEvent class, including scenarios for template failures and resend attempts.

Possibly related PRs

  • Retry Broadcast #1359: Adds the validate_retry_broadcast method and modifies the execute method in MessageBroadcastEvent, directly related to this PR.
  • Recurring Broadcast Fix  #1563: Updates the execute method to manage the retry count for broadcasts, relevant to the enhancements in this PR.
  • Duplicate Broadcast fix #1374: Enhances the logging of broadcast messages and includes a test for the behavior of resending broadcasts, aligning with the main PR's focus on improving the execution and logging of message broadcasts.
  • resend broadcast cli fix #1380: Modifies the command-line interface to include an is_resend parameter, which is relevant to the changes in the main PR that involve handling the is_resend flag in the execute method.
  • resend broadcast fix #1383: Focuses on the is_resend parameter in the CLI, connecting to the changes in the main PR regarding the execution flow of the MessageBroadcastEvent.
  • Template error handling #1565: Primarily focused on error handling for templates, this PR's modifications may indirectly relate to the overall robustness of the message broadcasting process discussed in the main PR.

Suggested reviewers

  • hiteshghuge
  • sushantpatade

Poem

🐰 In the meadow where broadcasts play,
A rabbit hops, brightening the day.
With templates ready and retries in sight,
We send our messages, taking flight!
Errors handled, logs so clear,
Hooray for changes, let’s all cheer! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (7)
kairon/events/definitions/message_broadcast.py (2)

Line range hint 39-44: Add docstring to validate_retry_broadcast method.

The method logic is correct, but it would benefit from proper documentation explaining its purpose, parameters, and possible exceptions.

Add a docstring like this:

def validate_retry_broadcast(self, event_id: Text):
+    """
+    Validates if the retry broadcasting limit has been reached for the given event.
+    
+    Args:
+        event_id (Text): The ID of the broadcast event to validate
+        
+    Raises:
+        AppException: If the retry broadcasting limit has been reached
+    """
    bot_settings = MongoProcessor.get_bot_settings(self.bot, self.user)

74-75: Enhance error logging with structured details.

While the error handling is correct, consider enhancing the error logging to include more context about the broadcast event.

-            logger.exception(e)
+            logger.exception(f"Broadcast failed for event_id={event_id}, is_resend={is_resend}: {str(e)}")
             exception = str(e)
             status = EVENT_STATUS.FAIL.value
kairon/shared/chat/broadcast/processor.py (2)

127-127: LGTM! Consider adding docstring for kwargs.

The addition of **kwargs parameter makes the method more flexible and supports the broadcast template fix. Consider adding a docstring to document the expected kwargs fields for better maintainability.

Add a docstring like this:

def update_broadcast_logs_with_template(reference_id: Text, event_id: Text, raw_template: List[Dict],
                                      log_type: MessageBroadcastLogType,
                                      retry_count: int = 0, **kwargs):
    """
    Update broadcast logs with template information and additional fields.

    Args:
        reference_id (Text): The reference ID for the broadcast
        event_id (Text): The event ID
        raw_template (List[Dict]): The template data
        log_type (MessageBroadcastLogType): The type of log
        retry_count (int, optional): Number of retries. Defaults to 0.
        **kwargs: Additional fields to update in the broadcast logs
    """

132-132: Consider adding field validation for kwargs.

While the current implementation works correctly, consider adding validation for the kwargs fields to prevent unintended updates to the broadcast logs.

Example implementation:

ALLOWED_UPDATE_FIELDS = {'status', 'errors', 'api_response'}  # add your allowed fields

def update_broadcast_logs_with_template(reference_id: Text, event_id: Text, raw_template: List[Dict],
                                      log_type: MessageBroadcastLogType,
                                      retry_count: int = 0, **kwargs):
    invalid_fields = set(kwargs.keys()) - ALLOWED_UPDATE_FIELDS
    if invalid_fields:
        raise ValueError(f"Invalid update fields: {invalid_fields}")
        
    message_broadcast_logs = MessageBroadcastLogs.objects(reference_id=reference_id,
                                                         event_id=event_id,
                                                         log_type=log_type,
                                                         retry_count=retry_count)
    message_broadcast_logs.update(template=raw_template, **kwargs)
tests/unit_test/events/events_test.py (3)

2169-2170: Combine @patch decorator onto a single line for clarity

The @patch decorator for send_template_message is split across two lines. Combining it into a single line improves readability.

Apply this diff:

-@patch("kairon.chat.handlers.channels.clients.whatsapp.dialog360.BSP360Dialog.send_template_message",
-       autospec=True)
+@patch("kairon.chat.handlers.channels.clients.whatsapp.dialog360.BSP360Dialog.send_template_message", autospec=True)

2231-2231: Use a more specific exception instead of generic Exception

Using a generic Exception in mock_list_templates.side_effect can obscure the nature of the error and make debugging more difficult. Consider using a more specific exception class or defining a custom exception.

Apply this diff:

-mock_list_templates.side_effect = Exception(template_exception)
+class TemplateLoadException(Exception):
+    pass
+
+mock_list_templates.side_effect = TemplateLoadException(template_exception)

2211-2228: Refactor template definition to avoid duplication

The template variable is defined multiple times across different test methods. To improve maintainability, consider defining the template once at the class level or using a fixture.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e58b75a and 656a2e4.

📒 Files selected for processing (4)
  • kairon/events/definitions/message_broadcast.py (2 hunks)
  • kairon/shared/channels/broadcast/whatsapp.py (4 hunks)
  • kairon/shared/chat/broadcast/processor.py (1 hunks)
  • tests/unit_test/events/events_test.py (2 hunks)
🔇 Additional comments (4)
kairon/events/definitions/message_broadcast.py (2)

58-58: LGTM: Improved status initialization.

Setting initial status to EVENT_STATUS.INITIATED.value provides better tracking of the event lifecycle.


Line range hint 63-71: Verify template handling in broadcast implementations.

The error handling looks good, but let's verify that all template-related edge cases are covered in the broadcast implementations.

✅ Verification successful

Let me gather more specific information about the template handling implementation.


Template handling implementation is complete and robust

The implementation shows comprehensive template handling with proper error management:

  • Template retrieval and validation in __get_template with exception handling
  • Detailed logging of template errors and execution status
  • Proper handling of template parameters and language codes
  • Robust retry mechanism with template state preservation
  • Complete error tracking through template_exception propagation

The changes align well with the PR objectives of fixing broadcast template issues, with all edge cases covered in the implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for template handling in broadcast implementations
echo "Checking template handling in broadcast implementations..."
rg -l "template" --type py | grep -i "broadcast"

# Search for template-related error handling
echo "Checking template error handling..."
ast-grep --pattern 'try {
  $$$
  template
  $$$
} catch {
  $$$
}'

Length of output: 557


Script:

#!/bin/bash
# Check template handling in WhatsApp broadcast
echo "Checking WhatsApp broadcast template handling..."
rg -A 10 "template" kairon/shared/channels/broadcast/whatsapp.py

# Check template handling in processor
echo "Checking broadcast processor template handling..."
rg -A 10 "template" kairon/shared/chat/broadcast/processor.py

# Check template-related error handling
echo "Checking template error handling in broadcast..."
rg -B 2 -A 5 "except.*template" --type py | grep -i broadcast

Length of output: 13506

kairon/shared/channels/broadcast/whatsapp.py (1)

92-97: Properly handle template_exception after template retrieval

In the __send_using_pyscript method, while you are capturing template_exception, there is no check or handling based on its value. If an exception occurred during template retrieval, it might affect subsequent operations.

Consider verifying whether template_exception needs to be checked and handled appropriately after retrieval to prevent potential issues downstream. Here's a script to check where template_exception is utilized:

tests/unit_test/events/events_test.py (1)

2252-2254: Verify mocked bot settings reflect expected configurations

The mocked get_bot_settings returns hardcoded values. Ensure these configurations match the scenarios being tested and consider parameterizing them for different test cases.

Comment on lines +156 to +158
template_name = required_logs[0]["template_name"]
language_code = required_logs[0]["language_code"]
template, template_exception = self.__get_template(template_name, language_code)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Check if required_logs is not empty before accessing

The code assumes that required_logs has at least one element. If it's empty, accessing required_logs[0] will raise an IndexError.

Apply this diff to add a check:

+if not required_logs:
+    logger.warning("No required logs found for resending broadcast.")
+    return

 template_name = required_logs[0]["template_name"]
 language_code = required_logs[0]["language_code"]
 template, template_exception = self.__get_template(template_name, language_code)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template_name = required_logs[0]["template_name"]
language_code = required_logs[0]["language_code"]
template, template_exception = self.__get_template(template_name, language_code)
if not required_logs:
logger.warning("No required logs found for resending broadcast.")
return
template_name = required_logs[0]["template_name"]
language_code = required_logs[0]["language_code"]
template, template_exception = self.__get_template(template_name, language_code)


for log in required_logs:
template_id = log["template_name"]
namespace = log["namespace"]
language_code = log["language_code"]
components = log["template_params"]
recipient = log["recipient"]
template = log["template"]
template = log.template if log.template else template
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct dictionary access for template in log

The code uses log.template, but log is a dictionary. This should be changed to log["template"] to prevent an AttributeError.

Apply this diff to fix the issue:

-template = log.template if log.template else template
+template = log["template"] if log.get("template") else template
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template = log.template if log.template else template
template = log["template"] if log.get("template") else template

@@ -105,7 +107,7 @@
namespace = template_config.get("namespace")
lang = template_config["language"]
template_params = self._get_template_parameters(template_config)
raw_template = self.__get_template(template_id, lang)
raw_template, template_exception = self.__get_template(template_id, lang)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure template_exception is handled after calling __get_template

In the __send_using_configuration method, template_exception is retrieved but not checked or acted upon. Unhandled exceptions might lead to unexpected behavior.

Apply this diff to handle template_exception:

 raw_template, template_exception = self.__get_template(template_id, lang)

+if template_exception:
+    # Handle the exception, for example, log it or raise an error
+    logger.error(f"Template exception occurred: {template_exception}")
+    raise AppException(f"Failed to retrieve template: {template_exception}")

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +205 to +217
template_exception = None
template = []
try:
for template in BSP360Dialog(self.bot, self.user).list_templates(**{"business_templates.name": name}):
if template.get("language") == language:
template = template.get("components")
break
return template, template_exception
except Exception as e:
logger.exception(e)
template_exception = str(e)
return template, template_exception

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid variable shadowing of template in __get_template method

Using template as both the list to return and the loop variable can cause confusion and potential errors. Consider renaming the loop variable.

Apply this diff to rename the loop variable:

 def __get_template(self, name: Text, language: Text):
     template_exception = None
     template_components = []
     try:
-        for template in BSP360Dialog(self.bot, self.user).list_templates(**{"business_templates.name": name}):
-            if template.get("language") == language:
-                template = template.get("components")
+        for tmpl in BSP360Dialog(self.bot, self.user).list_templates(**{"business_templates.name": name}):
+            if tmpl.get("language") == language:
+                template_components = tmpl.get("components")
                 break
-        return template, template_exception
+        return template_components, template_exception
     except Exception as e:
         logger.exception(e)
         template_exception = str(e)
-        return template, template_exception
+        return template_components, template_exception
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template_exception = None
template = []
try:
for template in BSP360Dialog(self.bot, self.user).list_templates(**{"business_templates.name": name}):
if template.get("language") == language:
template = template.get("components")
break
return template, template_exception
except Exception as e:
logger.exception(e)
template_exception = str(e)
return template, template_exception
template_exception = None
template_components = []
try:
for tmpl in BSP360Dialog(self.bot, self.user).list_templates(**{"business_templates.name": name}):
if tmpl.get("language") == language:
template_components = tmpl.get("components")
break
return template_components, template_exception
except Exception as e:
logger.exception(e)
template_exception = str(e)
return template_components, template_exception

Comment on lines +2290 to +2293
assert logged_config.pop("template_config") == []
assert logged_config == config

timestamp = datetime.utcnow()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid using pop in assertions to check dictionary contents

Using pop in assertions can lead to KeyError if the key is missing. It's safer to use get or check for the existence of the key before popping.

Consider refactoring as:

-logged_config.pop("_id")
-logged_config.pop("status")
-logged_config.pop("timestamp")
-assert logged_config.pop("template_config") == []
+assert logged_config.get("template_config") == []
+logged_config.pop("_id", None)
+logged_config.pop("status", None)
+logged_config.pop("timestamp", None)
+logged_config.pop("template_config", None)

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
tests/unit_test/events/events_test.py (4)

Line range hint 1287-1410: Consider adding assertions for template parameters

The test verifies broadcast logs but could be enhanced by adding explicit assertions for template parameters and their structure.

assert logs[0][0]['template_params'] == [{
    'type': 'header',
    'parameters': [{
        'type': 'document',
        'document': {
            'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm',
            'filename': 'Brochure.pdf'
        }
    }]
}]

Line range hint 2846-4002: Comprehensive test for resend broadcast functionality

Good coverage of:

  • Multiple retry scenarios
  • Error handling
  • Status tracking
  • Campaign metrics validation

However, consider extracting common test data setup into helper methods to reduce code duplication.

def setup_broadcast_test_data(self, bot, user, reference_id, template, timestamp):
    """Helper to setup common test data"""
    MessageBroadcastLogs(
        reference_id=reference_id,
        log_type="common",
        bot=bot,
        status="Completed",
        user=user,
        timestamp=timestamp,
        # ... other common fields
    ).save()
    # ... setup other required test data

Line range hint 4002-4554: Verify error code handling more explicitly

The test verifies meta error code handling but could be enhanced by:

  1. Adding assertions for specific error codes
  2. Testing boundary conditions
def test_meta_error_code_boundary_conditions(self):
    """Test boundary conditions for meta error codes"""
    # Test minimum error code
    assert not self.should_retry_broadcast({'code': 130000})
    # Test maximum error code  
    assert not self.should_retry_broadcast({'code': 139999})

5113-5113: Consider adding timeout tests for retry logic

The test covers multiple retries but should also verify timeout handling between retries.

@patch('time.sleep')  # Mock sleep to speed up tests
def test_retry_with_timeout(self, mock_sleep):
    """Test retry timeout handling"""
    # Setup test
    # Verify sleep is called between retries
    mock_sleep.assert_called_with(RETRY_TIMEOUT)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d8847a2 and 5481027.

📒 Files selected for processing (1)
  • tests/unit_test/events/events_test.py (12 hunks)
🔇 Additional comments (1)
tests/unit_test/events/events_test.py (1)

2165-2426: Well-structured test for template exception handling

The test case thoroughly validates the error handling when template loading fails. Good coverage of:

  • Mock setup for template loading failure
  • Verification of error propagation
  • Validation of error logging

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5481027 and e154860.

📒 Files selected for processing (1)
  • kairon/shared/channels/whatsapp/bsp/dialog360.py (1 hunks)
🧰 Additional context used
🪛 Ruff
kairon/shared/channels/whatsapp/bsp/dialog360.py

167-167: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🔇 Additional comments (1)
kairon/shared/channels/whatsapp/bsp/dialog360.py (1)

165-167: LGTM: Generic exception handling matches class pattern.

The addition of generic exception handling is consistent with other methods in the class and improves error visibility for template-related operations.

Let's verify the consistency of exception handling across template-related methods:

✅ Verification successful

Exception handling pattern is consistent across template operations

The verification confirms that the generic exception handling pattern is consistent across all template-related operations in the Dialog360 class:

  • All methods have a similar try-catch structure
  • They consistently catch both DoesNotExist and generic Exception
  • All exceptions are logged using logger.exception(e)
  • All caught exceptions are wrapped in AppException with appropriate error messages
  • The specific code change follows this established pattern

The implementation maintains code consistency and proper error handling practices within the class.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check exception handling patterns in template-related methods
# Expected: All template methods should have similar exception handling patterns

ast-grep --pattern 'def $method($$$) {
  try {
    $$$
  } catch (DoesNotExist as e) {
    $$$
  } catch (Exception as e) {
    $$$
  }
}'

Length of output: 140


Script:

#!/bin/bash
# Let's try a simpler pattern to check exception handling in the file
rg "except Exception as e:" -B 5 -A 3 "kairon/shared/channels/whatsapp/bsp/dialog360.py"

# Also check for other exception handling patterns
rg "except \w+ as \w+:" -B 5 -A 3 "kairon/shared/channels/whatsapp/bsp/dialog360.py"

Length of output: 4055

🧰 Tools
🪛 Ruff

167-167: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

Comment on lines +165 to +167
except Exception as e:
logger.exception(e)
raise AppException(str(e))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add exception chaining to preserve the original traceback.

The exception handling looks good, but we should preserve the original exception's traceback using exception chaining.

Apply this diff to chain the exceptions:

         except Exception as e:
             logger.exception(e)
-            raise AppException(str(e))
+            raise AppException(str(e)) from e

This change will help with debugging by preserving the full traceback of the original exception.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except Exception as e:
logger.exception(e)
raise AppException(str(e))
except Exception as e:
logger.exception(e)
raise AppException(str(e)) from e
🧰 Tools
🪛 Ruff

167-167: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant