From 9af8e863f7fb0fa8bea050ca022bbe4e05315d6d Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:10:01 +0530 Subject: [PATCH 1/2] feat: enable instance-level connection (#316) * chore: auto-release * feat:enable instance-level connection * lint --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 23 ++++++++-- test/test_suite_13.py | 14 ++++++ test/test_suite_14.py | 14 ++++++ test/test_suite_20.py | 45 ++++++++++++++++++- 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e7a2ba17..b6bf3278 100644 --- a/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -645,11 +645,14 @@ def create_connect_args(self, url): The given URL follows the style: `spanner:///projects/{project-id}/instances/{instance-id}/databases/{database-id}` + or `spanner:///projects/{project-id}/instances/{instance-id}`. For the latter, + database operations will be not be possible and if required a new engine with + database-id set will need to be created. """ match = re.match( ( r"^projects/(?P.+?)/instances/" - "(?P.+?)/databases/(?P.+?)$" + "(?P.+?)(/databases/(?P.+)|$)" ), url.database, ) @@ -1346,17 +1349,29 @@ def do_rollback(self, dbapi_connection): ): pass else: - trace_attributes = {"db.instance": dbapi_connection.database.name} + trace_attributes = { + "db.instance": dbapi_connection.database.name + if dbapi_connection.database + else "" + } with trace_call("SpannerSqlAlchemy.Rollback", trace_attributes): dbapi_connection.rollback() def do_commit(self, dbapi_connection): - trace_attributes = {"db.instance": dbapi_connection.database.name} + trace_attributes = { + "db.instance": dbapi_connection.database.name + if dbapi_connection.database + else "" + } with trace_call("SpannerSqlAlchemy.Commit", trace_attributes): dbapi_connection.commit() def do_close(self, dbapi_connection): - trace_attributes = {"db.instance": dbapi_connection.database.name} + trace_attributes = { + "db.instance": dbapi_connection.database.name + if dbapi_connection.database + else "" + } with trace_call("SpannerSqlAlchemy.Close", trace_attributes): dbapi_connection.close() diff --git a/test/test_suite_13.py b/test/test_suite_13.py index a5b2e3bb..0561de5d 100644 --- a/test/test_suite_13.py +++ b/test/test_suite_13.py @@ -2045,3 +2045,17 @@ def test_create_engine_w_invalid_client_object(self): with pytest.raises(ValueError): engine.connect() + + +class CreateEngineWithoutDatabaseTest(fixtures.TestBase): + def test_create_engine_wo_database(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + without passing database id in the + connection URL. + """ + engine = create_engine(get_db_url().split("/database")[0]) + with engine.connect() as connection: + assert connection.connection.database is None diff --git a/test/test_suite_14.py b/test/test_suite_14.py index a13477b3..3ff069b2 100644 --- a/test/test_suite_14.py +++ b/test/test_suite_14.py @@ -2378,3 +2378,17 @@ def test_create_engine_w_invalid_client_object(self): with pytest.raises(ValueError): engine.connect() + + +class CreateEngineWithoutDatabaseTest(fixtures.TestBase): + def test_create_engine_wo_database(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + without passing database id in the + connection URL. + """ + engine = create_engine(get_db_url().split("/database")[0]) + with engine.connect() as connection: + assert connection.connection.database is None diff --git a/test/test_suite_20.py b/test/test_suite_20.py index fb59b725..b4bf26fa 100644 --- a/test/test_suite_20.py +++ b/test/test_suite_20.py @@ -24,7 +24,7 @@ import time from unittest import mock -from google.cloud.spanner_v1 import RequestOptions +from google.cloud.spanner_v1 import RequestOptions, Client import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.engine import Inspector @@ -144,7 +144,7 @@ UnicodeTextTest as _UnicodeTextTest, _UnicodeFixture as __UnicodeFixture, ) # noqa: F401, F403 -from test._helpers import get_db_url +from test._helpers import get_db_url, get_project config.test_schema = "" @@ -3000,3 +3000,44 @@ def test_request_priority(self): engine = create_engine("sqlite:///database") with engine.connect() as connection: pass + + +class CreateEngineWithClientObjectTest(fixtures.TestBase): + def test_create_engine_w_valid_client_object(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + by passing custom Client object. + """ + client = Client(project=get_project()) + engine = create_engine(get_db_url(), connect_args={"client": client}) + with engine.connect() as connection: + assert connection.connection.instance._client == client + + def test_create_engine_w_invalid_client_object(self): + """ + SPANNER TEST: + + Check that if project id in url and custom Client + Object passed to enginer mismatch, error is thrown. + """ + client = Client(project="project_id") + engine = create_engine(get_db_url(), connect_args={"client": client}) + + with pytest.raises(ValueError): + engine.connect() + + +class CreateEngineWithoutDatabaseTest(fixtures.TestBase): + def test_create_engine_wo_database(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + without passing database id in the + connection URL. + """ + engine = create_engine(get_db_url().split("/database")[0]) + with engine.connect() as connection: + assert connection.connection.database is None From a4e85136e0e2f849378581287a491b16692695c3 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 17:07:01 +0530 Subject: [PATCH 2/2] chore(main): release 1.6.0 (#318) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d07cac51..1ecea6c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.6.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.5.0...v1.6.0) (2023-04-26) + + +### Features + +* Enable instance-level connection ([#316](https://github.com/googleapis/python-spanner-sqlalchemy/issues/316)) ([9af8e86](https://github.com/googleapis/python-spanner-sqlalchemy/commit/9af8e863f7fb0fa8bea050ca022bbe4e05315d6d)) + ## [1.5.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.4.0...v1.5.0) (2023-04-19) diff --git a/version.py b/version.py index 9d804245..d22bc465 100644 --- a/version.py +++ b/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.5.0" +__version__ = "1.6.0"