You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2022/09/14 12:25:12 UTC

[airflow] branch main updated: Work around pyupgrade edge cases (#26384)

This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 9444d9789b Work around pyupgrade edge cases (#26384)
9444d9789b is described below

commit 9444d9789bc88e1063d81d28e219446b2251c0e1
Author: Tzu-ping Chung <ur...@gmail.com>
AuthorDate: Wed Sep 14 20:25:01 2022 +0800

    Work around pyupgrade edge cases (#26384)
---
 .pre-commit-config.yaml                     |  8 +-------
 airflow/models/baseoperator.py              | 10 +++++++++-
 airflow/providers/google/cloud/hooks/gcs.py | 16 ++++++++++------
 3 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 60da9658e3..2d329ec4ba 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -213,13 +213,7 @@ repos:
       - id: pyupgrade
         name: Upgrade Python code automatically
         args: ["--py37-plus"]
-        # We need to exclude gcs hook from pyupgrade because it has public "list" command which clashes
-        # with `list` that is used as type
-        # Test Python tests if different kinds of typing including one that does not have
-        # __future__ annotations, so it should be left without automated upgrade
-        # BaseOperator is disabled because replacing ClassVar[List[Type with corresponding list/type causes the attr to fail
-        # see https://github.com/apache/airflow/pull/26290#issuecomment-1246014807
-        exclude: ^airflow/_vendor/|^airflow/providers/google/cloud/hooks/gcs.py$|^tests/decorators/test_python.py$|^airflow/models/baseoperator.py$
+        exclude: ^airflow/_vendor/
   - repo: https://github.com/pre-commit/pygrep-hooks
     rev: v1.9.0
     hooks:
diff --git a/airflow/models/baseoperator.py b/airflow/models/baseoperator.py
index aebbf4fa44..06845910be 100644
--- a/airflow/models/baseoperator.py
+++ b/airflow/models/baseoperator.py
@@ -1738,11 +1738,19 @@ def cross_downstream(
         task.set_downstream(to_tasks)
 
 
+# pyupgrade assumes all type annotations can be lazily evaluated, but this is
+# not the case for attrs-decorated classes, since cattrs needs to evaluate the
+# annotation expressions at runtime, and Python before 3.9.0 does not lazily
+# evaluate those. Putting the expression in a top-level assignment statement
+# communicates this runtime requirement to pyupgrade.
+BaseOperatorClassList = List[Type[BaseOperator]]
+
+
 @attr.s(auto_attribs=True)
 class BaseOperatorLink(metaclass=ABCMeta):
     """Abstract base class that defines how we get an operator link."""
 
-    operators: ClassVar[List[Type[BaseOperator]]] = []
+    operators: ClassVar[BaseOperatorClassList] = []
     """
     This property will be used by Airflow Plugins to find the Operators to which you want
     to assign this Operator Link
diff --git a/airflow/providers/google/cloud/hooks/gcs.py b/airflow/providers/google/cloud/hooks/gcs.py
index 8f27fd7c7d..599bae1455 100644
--- a/airflow/providers/google/cloud/hooks/gcs.py
+++ b/airflow/providers/google/cloud/hooks/gcs.py
@@ -29,7 +29,7 @@ from functools import partial
 from io import BytesIO
 from os import path
 from tempfile import NamedTemporaryFile
-from typing import IO, Callable, Generator, List, Optional, Sequence, Set, TypeVar, cast, overload
+from typing import IO, Callable, Generator, Sequence, TypeVar, cast, overload
 from urllib.parse import urlparse
 
 from google.api_core.exceptions import NotFound
@@ -48,6 +48,10 @@ from airflow.version import version
 RT = TypeVar('RT')
 T = TypeVar("T", bound=Callable)
 
+# GCSHook has a method named 'list' (to junior devs: please don't do this), so
+# we need to create an alias to prevent Mypy being confused.
+List = list
+
 # Use default timeout from google-cloud-storage
 DEFAULT_TIMEOUT = 60
 
@@ -127,7 +131,7 @@ class GCSHook(GoogleBaseHook):
     connection.
     """
 
-    _conn = None  # type: Optional[storage.Client]
+    _conn: storage.Client | None = None
 
     def __init__(
         self,
@@ -671,7 +675,7 @@ class GCSHook(GoogleBaseHook):
         except NotFound:
             self.log.info("Bucket %s not exists", bucket_name)
 
-    def list(self, bucket_name, versions=None, max_results=None, prefix=None, delimiter=None) -> list:
+    def list(self, bucket_name, versions=None, max_results=None, prefix=None, delimiter=None) -> List:
         """
         List all objects from the bucket with the give string prefix in name
 
@@ -1127,11 +1131,11 @@ class GCSHook(GoogleBaseHook):
         # Determine objects to copy and delete
         to_copy = source_names - destination_names
         to_delete = destination_names - source_names
-        to_copy_blobs = {source_names_index[a] for a in to_copy}  # type: Set[storage.Blob]
-        to_delete_blobs = {destination_names_index[a] for a in to_delete}  # type: Set[storage.Blob]
+        to_copy_blobs: set[storage.Blob] = {source_names_index[a] for a in to_copy}
+        to_delete_blobs: set[storage.Blob] = {destination_names_index[a] for a in to_delete}
         # Find names that are in both buckets
         names_to_check = source_names.intersection(destination_names)
-        to_rewrite_blobs = set()  # type: Set[storage.Blob]
+        to_rewrite_blobs: set[storage.Blob] = set()
         # Compare objects based on crc32
         for current_name in names_to_check:
             source_blob = source_names_index[current_name]