cloud-sql-python-connector 1.19.0__tar.gz → 1.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/PKG-INFO +1 -1
  2. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/PKG-INFO +1 -1
  3. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/connector.py +43 -1
  4. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/exceptions.py +7 -0
  5. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/resolver.py +12 -0
  6. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/version.py +1 -1
  7. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/LICENSE +0 -0
  8. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/README.md +0 -0
  9. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/SOURCES.txt +0 -0
  10. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/dependency_links.txt +0 -0
  11. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/requires.txt +0 -0
  12. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/top_level.txt +0 -0
  13. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/__init__.py +0 -0
  14. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/asyncpg.py +0 -0
  15. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/client.py +0 -0
  16. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/connection_info.py +0 -0
  17. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/connection_name.py +0 -0
  18. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/enums.py +0 -0
  19. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/instance.py +0 -0
  20. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/lazy.py +0 -0
  21. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/monitored_cache.py +0 -0
  22. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/pg8000.py +0 -0
  23. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/py.typed +0 -0
  24. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/pymysql.py +0 -0
  25. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/pytds.py +0 -0
  26. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/rate_limiter.py +0 -0
  27. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/refresh_utils.py +0 -0
  28. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/utils.py +0 -0
  29. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/pyproject.toml +0 -0
  30. {cloud_sql_python_connector-1.19.0 → cloud_sql_python_connector-1.20.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloud-sql-python-connector
3
- Version: 1.19.0
3
+ Version: 1.20.0
4
4
  Summary: Google Cloud SQL Python Connector library
5
5
  Author-email: Google LLC <googleapis-packages@google.com>
6
6
  License-Expression: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloud-sql-python-connector
3
- Version: 1.19.0
3
+ Version: 1.20.0
4
4
  Summary: Google Cloud SQL Python Connector library
5
5
  Author-email: Google LLC <googleapis-packages@google.com>
6
6
  License-Expression: Apache-2.0
@@ -34,6 +34,7 @@ from google.cloud.sql.connector.client import CloudSQLClient
34
34
  from google.cloud.sql.connector.enums import DriverMapping
35
35
  from google.cloud.sql.connector.enums import IPTypes
36
36
  from google.cloud.sql.connector.enums import RefreshStrategy
37
+ from google.cloud.sql.connector.exceptions import ClosedConnectorError
37
38
  from google.cloud.sql.connector.exceptions import ConnectorLoopError
38
39
  from google.cloud.sql.connector.instance import RefreshAheadCache
39
40
  from google.cloud.sql.connector.lazy import LazyRefreshCache
@@ -155,6 +156,7 @@ class Connector:
155
156
  # connection name string and enable_iam_auth boolean flag
156
157
  self._cache: dict[tuple[str, bool], MonitoredCache] = {}
157
158
  self._client: Optional[CloudSQLClient] = None
159
+ self._closed: bool = False
158
160
 
159
161
  # initialize credentials
160
162
  scopes = ["https://www.googleapis.com/auth/sqlservice.admin"]
@@ -244,6 +246,12 @@ class Connector:
244
246
  # connect runs sync database connections on background thread.
245
247
  # Async database connections should call 'connect_async' directly to
246
248
  # avoid hanging indefinitely.
249
+
250
+ # Check if the connector is closed before attempting to connect.
251
+ if self._closed:
252
+ raise ClosedConnectorError(
253
+ "Connection attempt failed because the connector has already been closed."
254
+ )
247
255
  connect_future = asyncio.run_coroutine_threadsafe(
248
256
  self.connect_async(instance_connection_string, driver, **kwargs),
249
257
  self._loop,
@@ -281,7 +289,13 @@ class Connector:
281
289
  and then subsequent attempt with IAM database authentication.
282
290
  KeyError: Unsupported database driver Must be one of pymysql, asyncpg,
283
291
  pg8000, and pytds.
292
+ RuntimeError: Connector has been closed. Cannot connect using a closed
293
+ Connector.
284
294
  """
295
+ if self._closed:
296
+ raise ClosedConnectorError(
297
+ "Connection attempt failed because the connector has already been closed."
298
+ )
285
299
  # check if event loop is running in current thread
286
300
  if self._loop != asyncio.get_running_loop():
287
301
  raise ConnectorLoopError(
@@ -376,6 +390,33 @@ class Connector:
376
390
  # the cache and re-raise the error
377
391
  await self._remove_cached(str(conn_name), enable_iam_auth)
378
392
  raise
393
+
394
+ # If the connector is configured with a custom DNS name, attempt to use
395
+ # that DNS name to connect to the instance. Fall back to the metadata IP
396
+ # address if the DNS name does not resolve to an IP address.
397
+ if conn_info.conn_name.domain_name and isinstance(self._resolver, DnsResolver):
398
+ try:
399
+ ips = await self._resolver.resolve_a_record(conn_info.conn_name.domain_name)
400
+ if ips:
401
+ ip_address = ips[0]
402
+ logger.debug(
403
+ f"['{instance_connection_string}']: Custom DNS name "
404
+ f"'{conn_info.conn_name.domain_name}' resolved to '{ip_address}', "
405
+ "using it to connect"
406
+ )
407
+ else:
408
+ logger.debug(
409
+ f"['{instance_connection_string}']: Custom DNS name "
410
+ f"'{conn_info.conn_name.domain_name}' resolved but returned no "
411
+ f"entries, using '{ip_address}' from instance metadata"
412
+ )
413
+ except Exception as e:
414
+ logger.debug(
415
+ f"['{instance_connection_string}']: Custom DNS name "
416
+ f"'{conn_info.conn_name.domain_name}' did not resolve to an IP "
417
+ f"address: {e}, using '{ip_address}' from instance metadata"
418
+ )
419
+
379
420
  logger.debug(f"['{conn_info.conn_name}']: Connecting to {ip_address}:3307")
380
421
  # format `user` param for automatic IAM database authn
381
422
  if enable_iam_auth:
@@ -477,9 +518,10 @@ class Connector:
477
518
  async def close_async(self) -> None:
478
519
  """Helper function to cancel the cache's tasks
479
520
  and close aiohttp.ClientSession."""
480
- await asyncio.gather(*[cache.close() for cache in self._cache.values()])
521
+ self._closed = True
481
522
  if self._client:
482
523
  await self._client.close()
524
+ await asyncio.gather(*[cache.close() for cache in self._cache.values()])
483
525
 
484
526
 
485
527
  async def create_async_connector(
@@ -84,3 +84,10 @@ class CacheClosedError(Exception):
84
84
  Exception to be raised when a ConnectionInfoCache can not be accessed after
85
85
  it is closed.
86
86
  """
87
+
88
+
89
+ class ClosedConnectorError(Exception):
90
+ """
91
+ Exception to be raised when a Connector is closed and connect method is
92
+ called on it.
93
+ """
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from typing import List
16
+
15
17
  import dns.asyncresolver
16
18
 
17
19
  from google.cloud.sql.connector.connection_name import _is_valid_domain
@@ -53,6 +55,16 @@ class DnsResolver(dns.asyncresolver.Resolver):
53
55
  )
54
56
  return conn_name
55
57
 
58
+ async def resolve_a_record(self, dns: str) -> List[str]:
59
+ try:
60
+ # Attempt to query the A records.
61
+ records = await super().resolve(dns, "A", raise_on_no_answer=True)
62
+ # return IP addresses as strings
63
+ return [record.to_text() for record in records]
64
+ except Exception:
65
+ # On any error, return empty list
66
+ return []
67
+
56
68
  async def query_dns(self, dns: str) -> ConnectionName:
57
69
  try:
58
70
  # Attempt to query the TXT records.
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "1.19.0"
15
+ __version__ = "1.20.0"