Repository: GoogleCloudPlatform/cloud-sql-python-connector
Pull request #1009 (2024-02-13 18:56:23)

refactor: remove loop argument from Instance
Barrier to async functionality is through `connect.connect_async` at which point the `Instance()` is configured. At this stage in execution flow we are already running with the given event loop so it is redundant  to pass it to  Instance and instead we should follow best practice and purely use  higher level `asyncio.create_task` which is recommended.


Patch:
diff --git a/google/cloud/sql/connector/connector.py b/google/cloud/sql/connector/connector.py
index 789f8b5..d4d3425 100755
--- a/google/cloud/sql/connector/connector.py
+++ b/google/cloud/sql/connector/connector.py
@@ -234,7 +234,6 @@ class Connector:
                 instance_connection_string,
                 self._client,
                 self._keys,
-                self._loop,
                 enable_iam_auth,
             )
             self._instances[instance_connection_string] = instance
diff --git a/google/cloud/sql/connector/instance.py b/google/cloud/sql/connector/instance.py
index 8c5f829..dda5eb9 100644
--- a/google/cloud/sql/connector/instance.py
+++ b/google/cloud/sql/connector/instance.py
@@ -143,19 +143,8 @@ class Instance:
         Enables automatic IAM database authentication for Postgres or MySQL
         instances.
     :type enable_iam_auth: bool
-
-    :param loop:
-        A new event loop for the refresh function to run in.
-    :type loop: asyncio.AbstractEventLoop
     """
 
-    # asyncio.AbstractEventLoop is used because the default loop,
-    # SelectorEventLoop, is usable on both Unix and Windows but has limited
-    # functionality on Windows. It is recommended to use ProactorEventLoop
-    # while developing on Windows.
-    # Link to Github issue:
-    # https://github.com/GoogleCloudPlatform/cloud-sql-python-connector/issues/22
-    _loop: asyncio.AbstractEventLoop
     _enable_iam_auth: bool
     _keys: asyncio.Future
     _instance_connection_string: str
@@ -173,7 +162,6 @@ class Instance:
         instance_connection_string: str,
         client: CloudSQLClient,
         keys: asyncio.Future,
-        loop: asyncio.AbstractEventLoop,
         enable_iam_auth: bool = False,
     ) -> None:
         # validate and parse instance connection name
@@ -183,11 +171,11 @@ class Instance:
         self._instance_connection_string = instance_connection_string
 
         self._enable_iam_auth = enable_iam_auth
-        self._loop = loop
         self._keys = keys
         self._client = client
         self._refresh_rate_limiter = AsyncRateLimiter(
-            max_capacity=2, rate=1 / 30, loop=self._loop
+            max_capacity=2,
+            rate=1 / 30,
         )
         self._refresh_in_progress = asyncio.locks.Event()
         self._current = self._schedule_refresh(0)
@@ -225,7 +213,7 @@ class Instance:
 
             logger.debug(f"['{self._instance_connection_string}']: Creating context")
 
-            metadata_task = self._loop.create_task(
+            metadata_task = asyncio.create_task(
                 self._client._get_metadata(
                     self._project,
                     self._region,
@@ -233,7 +221,7 @@ class Instance:
                 )
             )
 
-            ephemeral_task = self._loop.create_task(
+            ephemeral_task = asyncio.create_task(
                 self._client._get_ephemeral(
                     self._project,
                     self._instance,
@@ -306,7 +294,7 @@ class Instance:
                 logger.debug(f"['{self._instance_connection_string}']: Entering sleep")
                 if delay > 0:
                     await asyncio.sleep(delay)
-                refresh_task = self._loop.create_task(self._perform_refresh())
+                refresh_task = asyncio.create_task(self._perform_refresh())
                 refresh_data = await refresh_task
             except asyncio.CancelledError:
                 logger.debug(
@@ -337,7 +325,7 @@ class Instance:
             return refresh_data
 
         # schedule refresh task and return it
-        scheduled_task = self._loop.create_task(_refresh_task(self, delay))
+        scheduled_task = asyncio.create_task(_refresh_task(self, delay))
         return scheduled_task
 
     async def connect_info(


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index fcff0a2..8f3d780 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -138,13 +138,11 @@ async def fake_client(
 
 @pytest.fixture
 async def instance(fake_client: CloudSQLClient) -> AsyncGenerator[Instance, None]:
-    loop = asyncio.get_running_loop()
     keys = asyncio.create_task(generate_keys())
     instance = Instance(
         "test-project:test-region:test-instance",
         client=fake_client,
         keys=keys,
-        loop=loop,
     )
     yield instance
     await instance.close()
diff --git a/tests/unit/test_instance.py b/tests/unit/test_instance.py
index 9c570b2..c083d5b 100644
--- a/tests/unit/test_instance.py
+++ b/tests/unit/test_instance.py
@@ -305,7 +305,6 @@ async def test_ClientResponseError(
     """
     Test that detailed error message is applied to ClientResponseError.
     """
-    loop = asyncio.get_running_loop()
     # mock Cloud SQL Admin API calls with exceptions
     keys = asyncio.create_task(generate_keys())
     client = CloudSQLClient(
@@ -336,7 +335,6 @@ async def test_ClientResponseError(
             "my-project:my-region:my-instance",
             client,
             keys,
-            loop,
         )
         try:
             await instance._current
@@ -359,14 +357,12 @@ async def test_AutoIAMAuthNotSupportedError(fake_client: CloudSQLClient) -> None
     Test that AutoIAMAuthNotSupported exception is raised
     for SQL Server instances.
     """
-    loop = asyncio.get_running_loop()
     # generate client key pair
     keys = asyncio.create_task(generate_keys())
     instance = Instance(
         "test-project:test-region:sqlserver-instance",
         client=fake_client,
         keys=keys,
-        loop=loop,
         enable_iam_auth=True,
     )
     with pytest.raises(AutoIAMAuthNotSupported):