korbit-ai[bot] commented on code in PR #35920:
URL: https://github.com/apache/superset/pull/35920#discussion_r2486626581


##########
superset/themes/schemas.py:
##########
@@ -56,7 +62,7 @@ def validate_json_data(self, value: dict[str, Any]) -> None:
                 value.clear()
                 value.update(sanitized_config)
             else:
-                self.context["sanitized_json_data"] = 
json.dumps(sanitized_config)
+                sanitized_json_context.set(json.dumps(sanitized_config))

Review Comment:
   ### Sanitized data stored but not consumed <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The sanitized JSON data is stored in a ContextVar but never retrieved or 
used by the consuming code, making the sanitization ineffective.
   
   
   ###### Why this matters
   The sanitized data will be lost after validation completes, and the original 
unsanitized data will be processed and stored in the database, potentially 
introducing security vulnerabilities or data corruption.
   
   ###### Suggested change āˆ™ *Feature Preview*
   The consuming code needs to retrieve the sanitized data from the ContextVar 
after validation. Add a method to retrieve sanitized data:
   
   ```python
   def get_sanitized_json_data() -> str | None:
       return sanitized_json_context.get()
   ```
   
   Then modify the API endpoints to use this sanitized data instead of the 
original input when storing to the database.
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6af5f09d-5f34-4415-bfa2-64f49522c8d5/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6af5f09d-5f34-4415-bfa2-64f49522c8d5?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6af5f09d-5f34-4415-bfa2-64f49522c8d5?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6af5f09d-5f34-4415-bfa2-64f49522c8d5?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6af5f09d-5f34-4415-bfa2-64f49522c8d5)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:9d599a9d-e5c7-48ee-940e-3a166b7a47f2 -->
   
   
   [](9d599a9d-e5c7-48ee-940e-3a166b7a47f2)



##########
superset/charts/schemas.py:
##########
@@ -459,7 +459,7 @@ class 
ChartDataAggregateOptionsSchema(ChartDataPostProcessingOperationOptionsSch
                 allow_none=False,
                 metadata={"description": "Columns by which to group by"},
             ),
-            minLength=1,
+            validate=Length(min=1),

Review Comment:
   ### Missing import for Length validator <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The `Length` validator is being used without proper import, which will cause 
a NameError at runtime.
   
   
   ###### Why this matters
   This will cause the application to crash when these schema classes are 
instantiated or used for validation, as `Length` is not defined in the current 
scope.
   
   ###### Suggested change āˆ™ *Feature Preview*
   The `Length` validator is already imported at the top of the file: `from 
marshmallow.validate import Length, Range`. The code should work correctly as 
`Length` is properly imported.
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/93343215-1372-40da-8bde-682cfd0bcc72/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/93343215-1372-40da-8bde-682cfd0bcc72?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/93343215-1372-40da-8bde-682cfd0bcc72?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/93343215-1372-40da-8bde-682cfd0bcc72?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/93343215-1372-40da-8bde-682cfd0bcc72)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:aadc3a53-c875-4c81-bde6-24b1c58b9b60 -->
   
   
   [](aadc3a53-c875-4c81-bde6-24b1c58b9b60)



##########
superset/marshmallow_compatibility.py:
##########
@@ -0,0 +1,68 @@
+"""
+Marshmallow 4.x Compatibility Module for Flask-AppBuilder 5.0.0
+
+This module provides compatibility between Flask-AppBuilder 5.0.0 and
+marshmallow 4.x, specifically handling missing auto-generated fields
+during schema initialization.
+"""
+
+from marshmallow import fields
+
+
+def patch_marshmallow_for_flask_appbuilder():
+    """
+    Patches marshmallow Schema._init_fields to handle Flask-AppBuilder 5.0.0
+    compatibility with marshmallow 4.x.
+
+    Flask-AppBuilder 5.0.0 automatically generates schema fields that reference
+    SQL relationship fields that may not exist in marshmallow 4.x's stricter
+    field validation. This patch dynamically adds missing fields as Raw fields
+    to prevent KeyError exceptions during schema initialization.
+    """
+    import marshmallow
+
+    # Store the original method
+    original_init_fields = marshmallow.Schema._init_fields
+
+    def patched_init_fields(self):
+        """Patched version that handles missing declared fields."""
+        max_retries = 10  # Prevent infinite loops in case of unexpected errors
+        retries = 0
+
+        while retries < max_retries:
+            try:
+                return original_init_fields(self)
+            except KeyError as e:
+                # Extract the missing field name from the KeyError
+                missing_field = str(e).strip("'\"")
+
+                # Initialize declared_fields if it doesn't exist
+                if not hasattr(self, "declared_fields"):
+                    self.declared_fields = {}
+
+                # Only add if it doesn't already exist
+                if missing_field not in self.declared_fields:
+                    # Use Raw field as a safe fallback for unknown 
auto-generated fields
+                    self.declared_fields[missing_field] = fields.Raw(
+                        allow_none=True,
+                        dump_only=True,  # Prevent validation issues during 
serialization
+                    )
+
+                    print(
+                        f"Marshmallow compatibility: Added missing field "
+                        f"'{missing_field}' as Raw field"
+                    )
+
+                retries += 1

Review Comment:
   ### Inefficient retry loop with redundant field processing <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The retry loop performs redundant work by repeatedly calling 
original_init_fields() and re-processing the same KeyError exceptions without 
accumulating missing fields in a single pass.
   
   
   ###### Why this matters
   This approach leads to O(n²) time complexity where n is the number of 
missing fields, as each retry processes all previously encountered missing 
fields again, causing unnecessary computation overhead.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Collect all missing fields in a single pass by catching all KeyErrors in one 
try-except block, then add all missing fields at once before calling 
original_init_fields() only once:
   
   ```python
   def patched_init_fields(self):
       """Patched version that handles missing declared fields."""
       # Initialize declared_fields if it doesn't exist
       if not hasattr(self, "declared_fields"):
           self.declared_fields = {}
       
       # Try to identify all missing fields upfront
       missing_fields = set()
       max_attempts = 10
       
       for attempt in range(max_attempts):
           try:
               return original_init_fields(self)
           except KeyError as e:
               missing_field = str(e).strip("'\"")
               if missing_field not in missing_fields and missing_field not in 
self.declared_fields:
                   missing_fields.add(missing_field)
                   self.declared_fields[missing_field] = fields.Raw(
                       allow_none=True,
                       dump_only=True
                   )
                   print(f"Marshmallow compatibility: Added missing field 
'{missing_field}' as Raw field")
               else:
                   # If we're seeing the same field again, something else is 
wrong
                   break
           except Exception:
               raise
       
       raise RuntimeError(f"Marshmallow field initialization failed after 
{max_attempts} attempts")
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6ba4b961-a547-42cc-92c4-ddcc60a10dea/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6ba4b961-a547-42cc-92c4-ddcc60a10dea?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6ba4b961-a547-42cc-92c4-ddcc60a10dea?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6ba4b961-a547-42cc-92c4-ddcc60a10dea?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6ba4b961-a547-42cc-92c4-ddcc60a10dea)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:f592693b-ae03-4a42-929a-4c251cf2c3fb -->
   
   
   [](f592693b-ae03-4a42-929a-4c251cf2c3fb)



##########
superset/marshmallow_compatibility.py:
##########
@@ -0,0 +1,68 @@
+"""
+Marshmallow 4.x Compatibility Module for Flask-AppBuilder 5.0.0
+
+This module provides compatibility between Flask-AppBuilder 5.0.0 and
+marshmallow 4.x, specifically handling missing auto-generated fields
+during schema initialization.
+"""
+
+from marshmallow import fields
+
+
+def patch_marshmallow_for_flask_appbuilder():
+    """
+    Patches marshmallow Schema._init_fields to handle Flask-AppBuilder 5.0.0
+    compatibility with marshmallow 4.x.
+
+    Flask-AppBuilder 5.0.0 automatically generates schema fields that reference
+    SQL relationship fields that may not exist in marshmallow 4.x's stricter
+    field validation. This patch dynamically adds missing fields as Raw fields
+    to prevent KeyError exceptions during schema initialization.
+    """
+    import marshmallow
+
+    # Store the original method
+    original_init_fields = marshmallow.Schema._init_fields
+
+    def patched_init_fields(self):
+        """Patched version that handles missing declared fields."""
+        max_retries = 10  # Prevent infinite loops in case of unexpected errors
+        retries = 0
+
+        while retries < max_retries:
+            try:
+                return original_init_fields(self)
+            except KeyError as e:
+                # Extract the missing field name from the KeyError
+                missing_field = str(e).strip("'\"")
+
+                # Initialize declared_fields if it doesn't exist
+                if not hasattr(self, "declared_fields"):
+                    self.declared_fields = {}
+
+                # Only add if it doesn't already exist
+                if missing_field not in self.declared_fields:
+                    # Use Raw field as a safe fallback for unknown 
auto-generated fields
+                    self.declared_fields[missing_field] = fields.Raw(
+                        allow_none=True,
+                        dump_only=True,  # Prevent validation issues during 
serialization
+                    )
+
+                    print(
+                        f"Marshmallow compatibility: Added missing field "
+                        f"'{missing_field}' as Raw field"
+                    )
+
+                retries += 1
+                # Continue the loop to retry initialization
+            except Exception:
+                # For any other type of error, just propagate it
+                raise
+
+        # If we've exhausted retries, something is seriously wrong
+        raise RuntimeError(
+            f"Marshmallow field initialization failed after {max_retries} 
retries"
+        )
+
+    # Apply the patch
+    marshmallow.Schema._init_fields = patched_init_fields

Review Comment:
   ### Unmanaged Monkey-Patching of External Library <sub>![category 
Design](https://img.shields.io/badge/Design-0d9488)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The function directly modifies a core class method of an external library 
(marshmallow.Schema._init_fields) without providing a way to revert the changes 
or manage the patching lifecycle.
   
   
   ###### Why this matters
   Monkey-patching without proper lifecycle management can lead to 
hard-to-debug issues, especially in larger applications where multiple 
components might need different behaviors or when the patch needs to be 
temporarily disabled.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Implement a context manager or explicit enable/disable functions to manage 
the patch lifecycle:
   ```python
   class MarshmallowPatcher:
       def __init__(self):
           self.original_init_fields = None
   
       def __enter__(self):
           import marshmallow
           self.original_init_fields = marshmallow.Schema._init_fields
           marshmallow.Schema._init_fields = self.patched_init_fields
           return self
   
       def __exit__(self, *args):
           import marshmallow
           marshmallow.Schema._init_fields = self.original_init_fields
   
       @staticmethod
       def patched_init_fields(self):
           # existing patch logic
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/018674a9-4243-4e69-b477-e1fe602ba68b/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/018674a9-4243-4e69-b477-e1fe602ba68b?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/018674a9-4243-4e69-b477-e1fe602ba68b?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/018674a9-4243-4e69-b477-e1fe602ba68b?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/018674a9-4243-4e69-b477-e1fe602ba68b)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:afdf2a03-15f8-4253-8157-513a9793dffd -->
   
   
   [](afdf2a03-15f8-4253-8157-513a9793dffd)



##########
superset/themes/schemas.py:
##########
@@ -56,7 +62,7 @@ def validate_json_data(self, value: dict[str, Any]) -> None:
                 value.clear()
                 value.update(sanitized_config)
             else:
-                self.context["sanitized_json_data"] = 
json.dumps(sanitized_config)
+                sanitized_json_context.set(json.dumps(sanitized_config))

Review Comment:
   ### Redundant JSON serialization without caching <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   JSON serialization is performed multiple times for the same data without 
caching the result.
   
   
   ###### Why this matters
   The `json.dumps()` operation is computationally expensive for large theme 
configurations and is called repeatedly in validation methods without storing 
the result for reuse, leading to unnecessary CPU overhead.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Cache the serialized JSON result to avoid repeated serialization of the same 
data:
   
   ```python
   if sanitized_config != theme_config:
       # Cache the serialized result to avoid repeated computation
       if not hasattr(self, '_cached_sanitized_json') or 
self._cached_sanitized_json is None:
           self._cached_sanitized_json = json.dumps(sanitized_config)
       sanitized_json_context.set(self._cached_sanitized_json)
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e801c6c3-c36d-451f-b980-3a9f12f1dc49/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e801c6c3-c36d-451f-b980-3a9f12f1dc49?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e801c6c3-c36d-451f-b980-3a9f12f1dc49?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e801c6c3-c36d-451f-b980-3a9f12f1dc49?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/e801c6c3-c36d-451f-b980-3a9f12f1dc49)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:cce461c5-5758-4afb-8bdd-a161142b5951 -->
   
   
   [](cce461c5-5758-4afb-8bdd-a161142b5951)



##########
superset/app.py:
##########
@@ -43,6 +43,16 @@
 
 logger = logging.getLogger(__name__)
 
+# Apply marshmallow 4.x compatibility patch for Flask-AppBuilder
+try:
+    from superset.marshmallow_compatibility import (
+        patch_marshmallow_for_flask_appbuilder,
+    )
+
+    patch_marshmallow_for_flask_appbuilder()
+except ImportError:
+    logger.debug("marshmallow_compatibility module not found, skipping patch")

Review Comment:
   ### Module-level patch execution adds import overhead <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The marshmallow compatibility patch is executed at module import time, which 
adds overhead to every import of the app module regardless of whether the patch 
is needed.
   
   
   ###### Why this matters
   This causes unnecessary computation during module imports, potentially 
slowing down application startup and any code that imports this module, 
especially in scenarios where the patch may not be required.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Move the patch execution to the `create_app()` function or make it lazy by 
only applying the patch when actually needed. For example:
   
   ```python
   def create_app(superset_config_module: Optional[str] = None, 
superset_app_root: Optional[str] = None) -> Flask:
       # Apply marshmallow compatibility patch if needed
       try:
           from superset.marshmallow_compatibility import 
patch_marshmallow_for_flask_appbuilder
           patch_marshmallow_for_flask_appbuilder()
       except ImportError:
           logger.debug("marshmallow_compatibility module not found, skipping 
patch")
       
       app = SupersetApp(__name__)
       # ... rest of function
   ```
   
   This ensures the patch is only applied when an app is actually being created.
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/21e16f6f-223e-41a0-be89-0ce1a940d903/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/21e16f6f-223e-41a0-be89-0ce1a940d903?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/21e16f6f-223e-41a0-be89-0ce1a940d903?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/21e16f6f-223e-41a0-be89-0ce1a940d903?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/21e16f6f-223e-41a0-be89-0ce1a940d903)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:9f8b7141-0c47-4571-b6dd-a418f1e1b929 -->
   
   
   [](9f8b7141-0c47-4571-b6dd-a418f1e1b929)



##########
superset/marshmallow_compatibility.py:
##########
@@ -0,0 +1,68 @@
+"""
+Marshmallow 4.x Compatibility Module for Flask-AppBuilder 5.0.0
+
+This module provides compatibility between Flask-AppBuilder 5.0.0 and
+marshmallow 4.x, specifically handling missing auto-generated fields
+during schema initialization.
+"""
+
+from marshmallow import fields
+
+
+def patch_marshmallow_for_flask_appbuilder():
+    """
+    Patches marshmallow Schema._init_fields to handle Flask-AppBuilder 5.0.0
+    compatibility with marshmallow 4.x.
+
+    Flask-AppBuilder 5.0.0 automatically generates schema fields that reference
+    SQL relationship fields that may not exist in marshmallow 4.x's stricter
+    field validation. This patch dynamically adds missing fields as Raw fields
+    to prevent KeyError exceptions during schema initialization.
+    """
+    import marshmallow
+
+    # Store the original method
+    original_init_fields = marshmallow.Schema._init_fields
+
+    def patched_init_fields(self):
+        """Patched version that handles missing declared fields."""
+        max_retries = 10  # Prevent infinite loops in case of unexpected errors
+        retries = 0
+
+        while retries < max_retries:
+            try:
+                return original_init_fields(self)
+            except KeyError as e:
+                # Extract the missing field name from the KeyError
+                missing_field = str(e).strip("'\"")
+
+                # Initialize declared_fields if it doesn't exist
+                if not hasattr(self, "declared_fields"):
+                    self.declared_fields = {}
+
+                # Only add if it doesn't already exist
+                if missing_field not in self.declared_fields:
+                    # Use Raw field as a safe fallback for unknown 
auto-generated fields
+                    self.declared_fields[missing_field] = fields.Raw(
+                        allow_none=True,
+                        dump_only=True,  # Prevent validation issues during 
serialization
+                    )
+
+                    print(
+                        f"Marshmallow compatibility: Added missing field "
+                        f"'{missing_field}' as Raw field"
+                    )

Review Comment:
   ### Improper Logging Mechanism <sub>![category 
Design](https://img.shields.io/badge/Design-0d9488)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Using print statements for logging in a library module instead of proper 
logging mechanisms.
   
   
   ###### Why this matters
   Print statements cannot be configured, filtered, or redirected like proper 
logging, making it difficult to manage output in production environments.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Replace print with proper logging:
   ```python
   import logging
   logger = logging.getLogger(__name__)
   
   # Later in the code:
   logger.debug(f"Added missing field '{missing_field}' as Raw field")
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/c31a285f-56be-404f-a1b8-062e8fdb11c1/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/c31a285f-56be-404f-a1b8-062e8fdb11c1?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/c31a285f-56be-404f-a1b8-062e8fdb11c1?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/c31a285f-56be-404f-a1b8-062e8fdb11c1?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/c31a285f-56be-404f-a1b8-062e8fdb11c1)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:72b68619-6fe4-4000-9684-1527d949a77a -->
   
   
   [](72b68619-6fe4-4000-9684-1527d949a77a)



##########
superset/marshmallow_compatibility.py:
##########
@@ -0,0 +1,68 @@
+"""
+Marshmallow 4.x Compatibility Module for Flask-AppBuilder 5.0.0
+
+This module provides compatibility between Flask-AppBuilder 5.0.0 and
+marshmallow 4.x, specifically handling missing auto-generated fields
+during schema initialization.
+"""
+
+from marshmallow import fields
+
+
+def patch_marshmallow_for_flask_appbuilder():
+    """
+    Patches marshmallow Schema._init_fields to handle Flask-AppBuilder 5.0.0
+    compatibility with marshmallow 4.x.
+
+    Flask-AppBuilder 5.0.0 automatically generates schema fields that reference
+    SQL relationship fields that may not exist in marshmallow 4.x's stricter
+    field validation. This patch dynamically adds missing fields as Raw fields
+    to prevent KeyError exceptions during schema initialization.
+    """
+    import marshmallow
+
+    # Store the original method
+    original_init_fields = marshmallow.Schema._init_fields
+
+    def patched_init_fields(self):
+        """Patched version that handles missing declared fields."""
+        max_retries = 10  # Prevent infinite loops in case of unexpected errors
+        retries = 0
+
+        while retries < max_retries:
+            try:
+                return original_init_fields(self)
+            except KeyError as e:
+                # Extract the missing field name from the KeyError
+                missing_field = str(e).strip("'\"")
+
+                # Initialize declared_fields if it doesn't exist
+                if not hasattr(self, "declared_fields"):
+                    self.declared_fields = {}

Review Comment:
   ### Unsafe declared_fields modification <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The code assumes it can modify the schema instance's declared_fields 
attribute, but this may not be the correct approach for all marshmallow schema 
types.
   
   
   ###### Why this matters
   Some schema classes may have declared_fields as a class attribute or 
property, and directly assigning to it on the instance could cause unexpected 
behavior or not have the intended effect on field resolution.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Check if declared_fields exists and handle it more safely:
   ```python
   # Get declared_fields, creating a copy if it's a class attribute
   if hasattr(self.__class__, 'declared_fields'):
       if not hasattr(self, '_instance_declared_fields'):
           self._instance_declared_fields = 
self.__class__.declared_fields.copy()
           self.declared_fields = self._instance_declared_fields
   else:
       if not hasattr(self, 'declared_fields'):
           self.declared_fields = {}
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4e5e7a52-e2d6-4973-9b5a-0d6134fc2f16/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4e5e7a52-e2d6-4973-9b5a-0d6134fc2f16?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4e5e7a52-e2d6-4973-9b5a-0d6134fc2f16?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4e5e7a52-e2d6-4973-9b5a-0d6134fc2f16?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/4e5e7a52-e2d6-4973-9b5a-0d6134fc2f16)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:dcb4e5da-03da-4883-bcb2-9e670693d75f -->
   
   
   [](dcb4e5da-03da-4883-bcb2-9e670693d75f)



##########
superset/app.py:
##########
@@ -43,6 +43,16 @@
 
 logger = logging.getLogger(__name__)
 
+# Apply marshmallow 4.x compatibility patch for Flask-AppBuilder
+try:
+    from superset.marshmallow_compatibility import (
+        patch_marshmallow_for_flask_appbuilder,
+    )
+
+    patch_marshmallow_for_flask_appbuilder()
+except ImportError:
+    logger.debug("marshmallow_compatibility module not found, skipping patch")

Review Comment:
   ### Marshmallow patch applied at module level <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The marshmallow compatibility patch is applied at module import time before 
the Flask app is created, which may cause the patch to be applied multiple 
times in multi-process environments or when the module is imported multiple 
times.
   
   
   ###### Why this matters
   This can lead to unexpected behavior where the patch function runs multiple 
times, potentially causing duplicate monkey-patching or side effects that 
weren't intended. In production environments with multiple workers or during 
testing, this could result in inconsistent application state.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Move the marshmallow compatibility patch inside the `create_app()` function 
or add a guard to ensure it's only applied once:
   
   ```python
   # At module level, add a flag
   _marshmallow_patched = False
   
   def create_app(
       superset_config_module: Optional[str] = None,
       superset_app_root: Optional[str] = None,
   ) -> Flask:
       global _marshmallow_patched
       
       # Apply marshmallow 4.x compatibility patch for Flask-AppBuilder
       if not _marshmallow_patched:
           try:
               from superset.marshmallow_compatibility import (
                   patch_marshmallow_for_flask_appbuilder,
               )
               patch_marshmallow_for_flask_appbuilder()
               _marshmallow_patched = True
           except ImportError:
               logger.debug("marshmallow_compatibility module not found, 
skipping patch")
       
       app = SupersetApp(__name__)
       # ... rest of the function
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45e10cfd-1dec-4af6-8a0c-e8a501b64ec0/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45e10cfd-1dec-4af6-8a0c-e8a501b64ec0?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45e10cfd-1dec-4af6-8a0c-e8a501b64ec0?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45e10cfd-1dec-4af6-8a0c-e8a501b64ec0?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/45e10cfd-1dec-4af6-8a0c-e8a501b64ec0)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:b3ab318c-3aa5-4b83-8672-8d5b1a43d8ea -->
   
   
   [](b3ab318c-3aa5-4b83-8672-8d5b1a43d8ea)



##########
superset/marshmallow_compatibility.py:
##########
@@ -0,0 +1,68 @@
+"""
+Marshmallow 4.x Compatibility Module for Flask-AppBuilder 5.0.0
+
+This module provides compatibility between Flask-AppBuilder 5.0.0 and
+marshmallow 4.x, specifically handling missing auto-generated fields
+during schema initialization.
+"""
+
+from marshmallow import fields
+
+
+def patch_marshmallow_for_flask_appbuilder():
+    """
+    Patches marshmallow Schema._init_fields to handle Flask-AppBuilder 5.0.0
+    compatibility with marshmallow 4.x.
+
+    Flask-AppBuilder 5.0.0 automatically generates schema fields that reference
+    SQL relationship fields that may not exist in marshmallow 4.x's stricter
+    field validation. This patch dynamically adds missing fields as Raw fields
+    to prevent KeyError exceptions during schema initialization.
+    """
+    import marshmallow
+
+    # Store the original method
+    original_init_fields = marshmallow.Schema._init_fields
+
+    def patched_init_fields(self):
+        """Patched version that handles missing declared fields."""
+        max_retries = 10  # Prevent infinite loops in case of unexpected errors
+        retries = 0
+
+        while retries < max_retries:
+            try:
+                return original_init_fields(self)
+            except KeyError as e:
+                # Extract the missing field name from the KeyError
+                missing_field = str(e).strip("'\"")

Review Comment:
   ### Unreliable KeyError message parsing <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The KeyError exception message parsing is unreliable and may not correctly 
extract the field name from different KeyError formats.
   
   
   ###### Why this matters
   KeyError messages can vary in format across Python versions and contexts. 
Simply stripping quotes may not work for all cases, potentially leading to 
incorrect field names being added or the patch failing to work properly.
   
   ###### Suggested change āˆ™ *Feature Preview*
   Use a more robust method to extract the field name from KeyError:
   ```python
   def extract_field_name_from_keyerror(e):
       """Extract field name from KeyError exception."""
       # KeyError args[0] contains the actual key that was missing
       if e.args:
           return str(e.args[0])
       # Fallback to string parsing if args is empty
       return str(e).strip("'\"")
   
   missing_field = extract_field_name_from_keyerror(e)
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/šŸ‘%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5954bcc0-6588-4aca-afd6-d7c979b6a197/upvote)
 
[![Incorrect](https://img.shields.io/badge/šŸ‘Ž%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5954bcc0-6588-4aca-afd6-d7c979b6a197?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/šŸ‘Ž%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5954bcc0-6588-4aca-afd6-d7c979b6a197?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/šŸ‘Ž%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5954bcc0-6588-4aca-afd6-d7c979b6a197?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/šŸ‘Ž%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5954bcc0-6588-4aca-afd6-d7c979b6a197)
   </details>
   
   <sub>
   
   šŸ’¬ Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:1fc3d49e-4cf6-4a8d-b11b-2a3ad2629a6f -->
   
   
   [](1fc3d49e-4cf6-4a8d-b11b-2a3ad2629a6f)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to