AmosG commented on issue #51861:
URL: https://github.com/apache/airflow/issues/51861#issuecomment-3591637288

   I've successfully reproduced and fixed this issue! 
   I do think this is high priority - writing and debugging code is a critical 
task 
   
   ## Root Cause
   
   The problem occurs because **debuggers try to introspect the context 
dictionary** to display variables. In Airflow 3.x, the context contains 
`VariableAccessor`, `ConnectionAccessor`, and `MacrosAccessor` objects that use 
`__getattr__` for dynamic access.
   
   When the debugger calls `hasattr(obj, "__iter__")` to check if these objects 
are iterable, it triggers `__getattr__("__iter__")`, which attempts to fetch a 
variable named `"__iter__"` from the Airflow variable store, causing the 
infinite loop.
   
   ### Stack Trace Evidence
   
   ```python
   File "debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_safe_repr.py", line 
128, in _is_long_iter
       if not hasattr(obj, "__iter__"):
   File "airflow/sdk/execution_time/context.py", line 390, in __getattr__
       return _get_variable(key, self._deserialize_json)
   ```
   
   ## The Solution
   
   Add explicit `__iter__` methods to the Accessor classes in 
`airflow/sdk/execution_time/context.py`:
   
   ### Changes Required
   
   **1. VariableAccessor** (after `__repr__` method, around line 393):
   ```python
   def __iter__(self):
       raise TypeError(f"'{self.__class__.__name__}' object is not iterable")
   ```
   
   **2. ConnectionAccessor** (after `__repr__` method, around line 355):
   ```python
   def __iter__(self):
       raise TypeError(f"'{self.__class__.__name__}' object is not iterable")
   ```
   
   **3. MacrosAccessor** (after `__repr__` method, around line 439):
   ```python
   def __iter__(self):
       raise TypeError(f"'{self.__class__.__name__}' object is not iterable")
   ```
   
   **Optional Enhancement** - Add dunder method protection in `__getattr__` 
methods:
   ```python
   def __getattr__(self, key: str) -> Any:
       # Don't treat special methods (dunder methods) as variable/connection 
names
       if key.startswith('__') and key.endswith('__'):
           raise AttributeError(f"'{self.__class__.__name__}' object has no 
attribute '{key}'")
       # ... rest of existing code
   ```
   
   ## Why This Works
   
   - **Before**: `hasattr(obj, "__iter__")` → calls `__getattr__("__iter__")` → 
tries to fetch variable → hang
   - **After**: `hasattr(obj, "__iter__")` → returns `True` → calls 
`obj.__iter__()` → raises `TypeError` → debugger handles gracefully
   
   This follows Python's standard pattern for non-iterable objects.
   
   ## Testing Results
   
   After applying this fix:
   
   ✅ Debugger works perfectly with `**context` parameters  
   ✅ Variable access preserved: `context['var']['value'].my_var`  
   ✅ Connection access preserved: `context['conn'].my_conn`  
   ✅ Macro access preserved: `context['macros'].ds_add()`  
   ✅ Works with VSCode, Zed debuggers  (Problem did not seem to show on Pycharm)
   ✅ Tested on Airflow 3.0.2 and 3.1.3  
   
   ## Temporary Workaround
   
   Until this is fixed, users can:
   1. Use named parameters: `def my_task(ti=None, ds=None):` instead of 
`**context`
   2. Disable variable inspection in debugger settings
   3. Avoid breakpoints in functions with `**context`
   
   ## I'm Ready to Submit a PR
   
   This is a minimal, non-breaking fix that only adds ~15 lines of code. Would 
the maintainers like me to submit a PR with these changes?
   


-- 
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]

Reply via email to