kaxil commented on code in PR #71199:
URL: https://github.com/apache/airflow/pull/71199#discussion_r3761960439


##########
airflow-core/src/airflow/utils/helpers.py:
##########
@@ -313,11 +313,12 @@ def __getattr__(name: str):
     except KeyError:
         raise AttributeError(f"module '{__name__}' has no attribute '{name}'") 
from None
 
+    import importlib
     import warnings
 
     warnings.warn(
         f"{__name__}.{name} is deprecated. Use {modpath}.{name} instead.",
         DeprecationWarning,
         stacklevel=2,
     )
-    return getattr(__import__(modpath), name)
+    return getattr(importlib.import_module(modpath), name)

Review Comment:
   Can you add a regression test? 
`airflow-core/tests/unit/utils/test_helpers.py` already imports `helpers`, so 
it's a few lines:
   
   ```python
   @pytest.mark.parametrize(
       "name", ["render_template_as_native", "render_template_to_string", 
"prevent_duplicates"]
   )
   def test_deprecated_imports_resolve(name):
       with pytest.warns(DeprecationWarning):
           assert getattr(helpers, name) is not None
   ```
   
   Nothing in the tree touches `__deprecated_imports` today, which is why all 
three entries were broken rather than just one.



##########
airflow-core/src/airflow/utils/helpers.py:
##########
@@ -313,11 +313,12 @@ def __getattr__(name: str):
     except KeyError:
         raise AttributeError(f"module '{__name__}' has no attribute '{name}'") 
from None
 
+    import importlib
     import warnings
 
     warnings.warn(
         f"{__name__}.{name} is deprecated. Use {modpath}.{name} instead.",
         DeprecationWarning,

Review Comment:
   `stacklevel=2` attributes the warning to the caller's module, so a DAG 
author doing `from airflow.utils.helpers import render_template_as_native` gets 
a `DeprecationWarning` reported against their DAG file, which Python's default 
`ignore` filter drops. The `action="default"` filter Airflow installs in 
`configuration.py:58` is scoped to `module="airflow"` and doesn't match either. 
I confirmed locally that after your fix the shim resolves correctly but the 
notice never reaches stderr.
   
   We already have `airflow.utils.deprecation_tools.add_deprecated_classes` for 
this, and it gets both parts right: `importlib.import_module` plus 
`DeprecatedImportWarning`, which subclasses `FutureWarning` and so is shown by 
default. `airflow/io/__init__.py` uses the same `__name__: {...}` form. Worth 
replacing the hand-rolled block with:
   
   ```python
   from airflow.utils.deprecation_tools import add_deprecated_classes
   
   add_deprecated_classes(
       {
           __name__: {
               "render_template_as_native": 
"airflow.sdk.definitions.context.render_template_as_native",
               "render_template_to_string": 
"airflow.sdk.definitions.context.render_template_to_string",
               "prevent_duplicates": 
"airflow.sdk.definitions.mappedoperator.prevent_duplicates",
           }
       },
       package=__name__,
   )
   ```
   
   which lets both `__getattr__` and `__deprecated_imports` go away.



##########
airflow-core/src/airflow/utils/helpers.py:
##########
@@ -313,11 +313,12 @@ def __getattr__(name: str):
     except KeyError:
         raise AttributeError(f"module '{__name__}' has no attribute '{name}'") 
from None
 
+    import importlib

Review Comment:
   Minor: `importlib` is part of the import machinery and always loaded, so 
this can sit at the top of the file with the rest of the imports. Moot if you 
take the `add_deprecated_classes` route above.



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