From 6273d049aa779adac3a0faf59ce7ef1c41b8c12a Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 5 Jul 2022 18:45:37 +0000 Subject: [PATCH 1/9] chore(python): drop python 3.6 Source-Link: https://github.com/googleapis/synthtool/commit/4f89b13af10d086458f9b379e56a614f9d6dab7b Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:e7bb19d47c13839fe8c147e50e02e8b6cf5da8edd1af8b82208cd6f66cc2829c --- .github/.OwlBot.lock.yaml | 4 +- CONTRIBUTING.rst | 6 +- README.rst | 210 +++--------------- noxfile.py | 99 +++++---- samples/samples/noxfile.py | 2 +- .../templates/install_deps.tmpl.rst | 2 +- 6 files changed, 96 insertions(+), 227 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 4748c273cb..1ce6085235 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:a5d81b61dfd1a432d3c03f51a25d2e71b37be24da509966d50724aea7c57c5c2 -# created: 2022-07-04T12:33:08.125873124Z + digest: sha256:e7bb19d47c13839fe8c147e50e02e8b6cf5da8edd1af8b82208cd6f66cc2829c +# created: 2022-07-05T18:31:20.838186805Z diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 3c3bb87750..15a1381764 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -22,7 +22,7 @@ In order to add a feature: documentation. - The feature must work fully on the following CPython versions: - 3.6, 3.7, 3.8, 3.9 and 3.10 on both UNIX and Windows. + 3.7, 3.8, 3.9 and 3.10 on both UNIX and Windows. - The feature must not add unnecessary dependencies (where "unnecessary" is of course subjective, but new dependencies should @@ -221,13 +221,11 @@ Supported Python Versions We support: -- `Python 3.6`_ - `Python 3.7`_ - `Python 3.8`_ - `Python 3.9`_ - `Python 3.10`_ -.. _Python 3.6: https://docs.python.org/3.6/ .. _Python 3.7: https://docs.python.org/3.7/ .. _Python 3.8: https://docs.python.org/3.8/ .. _Python 3.9: https://docs.python.org/3.9/ @@ -239,7 +237,7 @@ Supported versions can be found in our ``noxfile.py`` `config`_. .. _config: https://github.com/googleapis/python-spanner/blob/main/noxfile.py -We also explicitly decided to support Python 3 beginning with version 3.6. +We also explicitly decided to support Python 3 beginning with version 3.7. Reasons for this include: - Encouraging use of newest versions of Python 3 diff --git a/README.rst b/README.rst index 0acf69fcba..84f15415bd 100644 --- a/README.rst +++ b/README.rst @@ -1,29 +1,22 @@ -Python Client for Cloud Spanner -=============================== +Python Client for Cloud Spanner API +=================================== -|GA| |pypi| |versions| - -`Cloud Spanner`_ is the world's first fully managed relational database service -to offer both strong consistency and horizontal scalability for -mission-critical online transaction processing (OLTP) applications. With Cloud -Spanner you enjoy all the traditional benefits of a relational database; but -unlike any other relational database service, Cloud Spanner scales horizontally -to hundreds or thousands of servers to handle the biggest transactional -workloads. +|stable| |pypi| |versions| +`Cloud Spanner API`_: - `Client Library Documentation`_ - `Product Documentation`_ -.. |GA| image:: https://img.shields.io/badge/support-GA-gold.svg - :target: https://github.com/googleapis/google-cloud-python/blob/main/README.rst#general-availability +.. |stable| image:: https://img.shields.io/badge/support-stable-gold.svg + :target: https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels .. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-spanner.svg :target: https://pypi.org/project/google-cloud-spanner/ .. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-spanner.svg :target: https://pypi.org/project/google-cloud-spanner/ -.. _Cloud Spanner: https://cloud.google.com/spanner/ +.. _Cloud Spanner API: https://cloud.google.com/spanner/docs/ .. _Client Library Documentation: https://cloud.google.com/python/docs/reference/spanner/latest -.. _Product Documentation: https://cloud.google.com/spanner/docs +.. _Product Documentation: https://cloud.google.com/spanner/docs/ Quick Start ----------- @@ -32,12 +25,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ -3. `Enable the Google Cloud Spanner API.`_ +3. `Enable the Cloud Spanner API.`_ 4. `Setup Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project -.. _Enable the Google Cloud Spanner API.: https://cloud.google.com/spanner +.. _Enable the Cloud Spanner API.: https://cloud.google.com/spanner/docs/ .. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation @@ -54,14 +47,25 @@ dependencies. .. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ +Code samples and snippets +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Code samples and snippets live in the `samples/` folder. + + Supported Python Versions ^^^^^^^^^^^^^^^^^^^^^^^^^ -Python >= 3.6 +Our client libraries are compatible with all current [active](https://devguide.python.org/devcycle/#in-development-main-branch) and [maintenance](https://devguide.python.org/devcycle/#maintenance-branches) versions of +Python. -Deprecated Python Versions -^^^^^^^^^^^^^^^^^^^^^^^^^^ -Python == 2.7. -Python == 3.5. +Python >= 3.7 + +Unsupported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Python <= 3.6 + +If you are using an [end-of-life](https://devguide.python.org/devcycle/#end-of-life-branches) +version of Python, we recommend that you update as soon as possible to an actively supported version. Mac/Linux @@ -85,159 +89,15 @@ Windows \Scripts\activate \Scripts\pip.exe install google-cloud-spanner - -Example Usage -------------- - - -Executing Arbitrary SQL in a Transaction -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Generally, to work with Cloud Spanner, you will want a transaction. The -preferred mechanism for this is to create a single function, which executes -as a callback to ``database.run_in_transaction``: - -.. code:: python - - # First, define the function that represents a single "unit of work" - # that should be run within the transaction. - def update_anniversary(transaction, person_id, unix_timestamp): - # The query itself is just a string. - # - # The use of @parameters is recommended rather than doing your - # own string interpolation; this provides protections against - # SQL injection attacks. - query = """SELECT anniversary FROM people - WHERE id = @person_id""" - - # When executing the SQL statement, the query and parameters are sent - # as separate arguments. When using parameters, you must specify - # both the parameters themselves and their types. - row = transaction.execute_sql( - query=query, - params={'person_id': person_id}, - param_types={ - 'person_id': types.INT64_PARAM_TYPE, - }, - ).one() - - # Now perform an update on the data. - old_anniversary = row[0] - new_anniversary = _compute_anniversary(old_anniversary, years) - transaction.update( - 'people', - ['person_id', 'anniversary'], - [person_id, new_anniversary], - ) - - # Actually run the `update_anniversary` function in a transaction. - database.run_in_transaction(update_anniversary, - person_id=42, - unix_timestamp=1335020400, - ) - - -Select records using a Transaction -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once you have a transaction object (such as the first argument sent to -``run_in_transaction``), reading data is easy: - -.. code:: python - - # Define a SELECT query. - query = """SELECT e.first_name, e.last_name, p.telephone - FROM employees as e, phones as p - WHERE p.employee_id == e.employee_id""" - - # Execute the query and return results. - result = transaction.execute_sql(query) - for row in result.rows: - print(row) - - -Insert records using Data Manipulation Language (DML) with a Transaction -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Use the ``execute_update()`` method to execute a DML statement: - -.. code:: python - - spanner_client = spanner.Client() - instance = spanner_client.instance(instance_id) - database = instance.database(database_id) - - def insert_singers(transaction): - row_ct = transaction.execute_update( - "INSERT Singers (SingerId, FirstName, LastName) " - " VALUES (10, 'Virginia', 'Watson')" - ) - - print("{} record(s) inserted.".format(row_ct)) - - database.run_in_transaction(insert_singers) - - -Insert records using Mutations with a Transaction -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To add one or more records to a table, use ``insert``: - -.. code:: python - - transaction.insert( - 'citizens', - columns=['email', 'first_name', 'last_name', 'age'], - values=[ - ['phred@exammple.com', 'Phred', 'Phlyntstone', 32], - ['bharney@example.com', 'Bharney', 'Rhubble', 31], - ], - ) - - -Update records using Data Manipulation Language (DML) with a Transaction -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - spanner_client = spanner.Client() - instance = spanner_client.instance(instance_id) - database = instance.database(database_id) - - def update_albums(transaction): - row_ct = transaction.execute_update( - "UPDATE Albums " - "SET MarketingBudget = MarketingBudget * 2 " - "WHERE SingerId = 1 and AlbumId = 1" - ) - - print("{} record(s) updated.".format(row_ct)) - - database.run_in_transaction(update_albums) - - -Update records using Mutations with a Transaction -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``Transaction.update`` updates one or more existing records in a table. Fails -if any of the records does not already exist. - -.. code:: python - - transaction.update( - 'citizens', - columns=['email', 'age'], - values=[ - ['phred@exammple.com', 33], - ['bharney@example.com', 32], - ], - ) - - Next Steps ~~~~~~~~~~ -- See the `Client Library Documentation`_ to learn how to connect to Cloud - Spanner using this Client Library. -- Read the `Product documentation`_ to learn - more about the product and see How-to Guides. +- Read the `Client Library Documentation`_ for Cloud Spanner API + to see other available methods on the client. +- Read the `Cloud Spanner API Product documentation`_ to learn + more about the product and see How-to Guides. +- View this `README`_ to see the full list of Cloud + APIs that we cover. + +.. _Cloud Spanner API Product documentation: https://cloud.google.com/spanner/docs/ +.. _README: https://github.com/googleapis/google-cloud-python/blob/main/README.rst diff --git a/noxfile.py b/noxfile.py index 42151a22f9..50c963cd4e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -31,7 +31,7 @@ DEFAULT_PYTHON_VERSION = "3.8" -UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] +UNIT_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] UNIT_TEST_STANDARD_DEPENDENCIES = [ "mock", "asyncmock", @@ -238,8 +238,7 @@ def install_systemtest_dependencies(session, *constraints): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) -@nox.parametrize("database_dialect", ["GOOGLE_STANDARD_SQL", "POSTGRESQL"]) -def system(session, database_dialect): +def system(session): """Run the system test suite.""" constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" @@ -257,9 +256,6 @@ def system(session, database_dialect): session.skip( "Credentials or emulator host must be set via environment variable" ) - # If POSTGRESQL tests and Emulator, skip the tests - if os.environ.get("SPANNER_EMULATOR_HOST") and database_dialect == "POSTGRESQL": - session.skip("Postgresql is not supported by Emulator yet.") # Install pyopenssl for mTLS testing. if os.environ.get("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true": @@ -281,10 +277,6 @@ def system(session, database_dialect): f"--junitxml=system_{session.python}_sponge_log.xml", system_test_path, *session.posargs, - env={ - "SPANNER_DATABASE_DIALECT": database_dialect, - "SKIP_BACKUP_TESTS": "true", - }, ) if system_test_folder_exists: session.run( @@ -293,10 +285,6 @@ def system(session, database_dialect): f"--junitxml=system_{session.python}_sponge_log.xml", system_test_folder_path, *session.posargs, - env={ - "SPANNER_DATABASE_DIALECT": database_dialect, - "SKIP_BACKUP_TESTS": "true", - }, ) @@ -374,28 +362,15 @@ def docfx(session): def prerelease_deps(session): """Run all tests with prerelease versions of dependencies installed.""" - prerel_deps = [ - "protobuf", - "googleapis-common-protos", - "google-auth", - "grpcio", - "grpcio-status", - "google-api-core", - "proto-plus", - # dependencies of google-auth - "cryptography", - "pyasn1", - ] - - for dep in prerel_deps: - session.install("--pre", "--no-deps", "--upgrade", dep) - - # Remaining dependencies - other_deps = ["requests"] - session.install(*other_deps) - + # Install all dependencies + session.install("-e", ".[all, tests, tracing]") session.install(*UNIT_TEST_STANDARD_DEPENDENCIES) - session.install(*SYSTEM_TEST_STANDARD_DEPENDENCIES) + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python # version, the first version we test with in the unit tests sessions has a @@ -409,19 +384,44 @@ def prerelease_deps(session): constraints_text = constraints_file.read() # Ignore leading whitespace and comment lines. - deps = [ + constraints_deps = [ match.group(1) for match in re.finditer( r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE ) ] - # Don't overwrite prerelease packages. - deps = [dep for dep in deps if dep not in prerel_deps] - # We use --no-deps to ensure that pre-release versions aren't overwritten - # by the version ranges in setup.py. - session.install(*deps) - session.install("--no-deps", "-e", ".[all]") + session.install(*constraints_deps) + + if os.path.exists("samples/snippets/requirements.txt"): + session.install("-r", "samples/snippets/requirements.txt") + + if os.path.exists("samples/snippets/requirements-test.txt"): + session.install("-r", "samples/snippets/requirements-test.txt") + + prerel_deps = [ + "protobuf", + # dependency of grpc + "six", + "googleapis-common-protos", + "grpcio", + "grpcio-status", + "google-api-core", + "proto-plus", + "google-cloud-testutils", + # dependencies of google-cloud-testutils" + "click", + ] + + for dep in prerel_deps: + session.install("--pre", "--no-deps", "--upgrade", dep) + + # Remaining dependencies + other_deps = [ + "requests", + "google-auth", + ] + session.install(*other_deps) # Print out prerelease package versions session.run( @@ -430,5 +430,16 @@ def prerelease_deps(session): session.run("python", "-c", "import grpc; print(grpc.__version__)") session.run("py.test", "tests/unit") - session.run("py.test", "tests/system") - session.run("py.test", "samples/snippets") + + system_test_path = os.path.join("tests", "system.py") + system_test_folder_path = os.path.join("tests", "system") + + # Only run system tests if found. + if os.path.exists(system_test_path) or os.path.exists(system_test_folder_path): + session.run("py.test", "tests/system") + + snippets_test_path = os.path.join("samples", "snippets") + + # Only run samples tests if found. + if os.path.exists(snippets_test_path): + session.run("py.test", "samples/snippets") diff --git a/samples/samples/noxfile.py b/samples/samples/noxfile.py index 38bb0a572b..5fcb9d7461 100644 --- a/samples/samples/noxfile.py +++ b/samples/samples/noxfile.py @@ -89,7 +89,7 @@ def get_pytest_env_vars() -> Dict[str, str]: # DO NOT EDIT - automatically generated. # All versions used to test samples. -ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] +ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] diff --git a/scripts/readme-gen/templates/install_deps.tmpl.rst b/scripts/readme-gen/templates/install_deps.tmpl.rst index 275d649890..6f069c6c87 100644 --- a/scripts/readme-gen/templates/install_deps.tmpl.rst +++ b/scripts/readme-gen/templates/install_deps.tmpl.rst @@ -12,7 +12,7 @@ Install Dependencies .. _Python Development Environment Setup Guide: https://cloud.google.com/python/setup -#. Create a virtualenv. Samples are compatible with Python 3.6+. +#. Create a virtualenv. Samples are compatible with Python 3.7+. .. code-block:: bash From 91c2f6e5899855acdcca4bfdbb5b420ea9da51c4 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 7 Jul 2022 16:00:16 +0000 Subject: [PATCH 2/9] add api_description to .repo-metadata.json --- .repo-metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.repo-metadata.json b/.repo-metadata.json index 50dad4805c..9fccb137ca 100644 --- a/.repo-metadata.json +++ b/.repo-metadata.json @@ -13,5 +13,6 @@ "requires_billing": true, "default_version": "v1", "codeowner_team": "@googleapis/api-spanner-python", - "api_shortname": "spanner" + "api_shortname": "spanner", + "api_description": "is a fully managed, mission-critical, \nrelational database service that offers transactional consistency at global scale, \nschemas, SQL (ANSI 2011 with extensions), and automatic, synchronous replication \nfor high availability.\n\nBe sure to activate the Cloud Spanner API on the Developer's Console to\nuse Cloud Spanner from your project." } From f75ebade9e0130d15528255b41d011b0e19f1c34 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 7 Jul 2022 16:01:05 +0000 Subject: [PATCH 3/9] require python 3.7+ in setup.py --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 1bd54bf961..2e03f33ebe 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,6 @@ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -103,7 +102,7 @@ namespace_packages=namespaces, install_requires=dependencies, extras_require=extras, - python_requires=">=3.6", + python_requires=">=3.7", include_package_data=True, zip_safe=False, ) From ce9d7c8887f47014b02572029a625ae08bf13393 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 7 Jul 2022 16:01:37 +0000 Subject: [PATCH 4/9] remove python 3.6 sample configs --- .kokoro/samples/python3.6/common.cfg | 40 --------------------- .kokoro/samples/python3.6/continuous.cfg | 7 ---- .kokoro/samples/python3.6/periodic-head.cfg | 11 ------ .kokoro/samples/python3.6/periodic.cfg | 6 ---- .kokoro/samples/python3.6/presubmit.cfg | 6 ---- 5 files changed, 70 deletions(-) delete mode 100644 .kokoro/samples/python3.6/common.cfg delete mode 100644 .kokoro/samples/python3.6/continuous.cfg delete mode 100644 .kokoro/samples/python3.6/periodic-head.cfg delete mode 100644 .kokoro/samples/python3.6/periodic.cfg delete mode 100644 .kokoro/samples/python3.6/presubmit.cfg diff --git a/.kokoro/samples/python3.6/common.cfg b/.kokoro/samples/python3.6/common.cfg deleted file mode 100644 index 76530dc98b..0000000000 --- a/.kokoro/samples/python3.6/common.cfg +++ /dev/null @@ -1,40 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Specify which tests to run -env_vars: { - key: "RUN_TESTS_SESSION" - value: "py-3.6" -} - -# Declare build specific Cloud project. -env_vars: { - key: "BUILD_SPECIFIC_GCLOUD_PROJECT" - value: "python-docs-samples-tests-py36" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-spanner/.kokoro/test-samples.sh" -} - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker" -} - -# Download secrets for samples -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples" - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "python-spanner/.kokoro/trampoline_v2.sh" \ No newline at end of file diff --git a/.kokoro/samples/python3.6/continuous.cfg b/.kokoro/samples/python3.6/continuous.cfg deleted file mode 100644 index 7218af1499..0000000000 --- a/.kokoro/samples/python3.6/continuous.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "True" -} - diff --git a/.kokoro/samples/python3.6/periodic-head.cfg b/.kokoro/samples/python3.6/periodic-head.cfg deleted file mode 100644 index b6133a1180..0000000000 --- a/.kokoro/samples/python3.6/periodic-head.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "True" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-spanner/.kokoro/test-samples-against-head.sh" -} diff --git a/.kokoro/samples/python3.6/periodic.cfg b/.kokoro/samples/python3.6/periodic.cfg deleted file mode 100644 index 71cd1e597e..0000000000 --- a/.kokoro/samples/python3.6/periodic.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "False" -} diff --git a/.kokoro/samples/python3.6/presubmit.cfg b/.kokoro/samples/python3.6/presubmit.cfg deleted file mode 100644 index a1c8d9759c..0000000000 --- a/.kokoro/samples/python3.6/presubmit.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "True" -} \ No newline at end of file From c63e25d5dbd9eead5d8976bab72de7387f22c9b5 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Thu, 7 Jul 2022 16:12:07 +0000 Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 84f15415bd..3ab348e92d 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,13 @@ Python Client for Cloud Spanner API |stable| |pypi| |versions| -`Cloud Spanner API`_: +`Cloud Spanner API`_: is a fully managed, mission-critical, +relational database service that offers transactional consistency at global scale, +schemas, SQL (ANSI 2011 with extensions), and automatic, synchronous replication +for high availability. + +Be sure to activate the Cloud Spanner API on the Developer's Console to +use Cloud Spanner from your project. - `Client Library Documentation`_ - `Product Documentation`_ From e6bbc47e085d622790cf0f70cca0bdae927f09f6 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Sat, 9 Jul 2022 09:52:05 +0000 Subject: [PATCH 6/9] exclude templated README --- README.rst | 213 +++++++++++++++++++++++++++++++++++++++++++---------- owlbot.py | 1 + 2 files changed, 175 insertions(+), 39 deletions(-) diff --git a/README.rst b/README.rst index 3ab348e92d..bebfe1fd5d 100644 --- a/README.rst +++ b/README.rst @@ -1,28 +1,29 @@ -Python Client for Cloud Spanner API -=================================== +Python Client for Cloud Spanner +=============================== -|stable| |pypi| |versions| +|GA| |pypi| |versions| -`Cloud Spanner API`_: is a fully managed, mission-critical, -relational database service that offers transactional consistency at global scale, -schemas, SQL (ANSI 2011 with extensions), and automatic, synchronous replication -for high availability. +`Cloud Spanner`_ is the world's first fully managed relational database service +to offer both strong consistency and horizontal scalability for +mission-critical online transaction processing (OLTP) applications. With Cloud +Spanner you enjoy all the traditional benefits of a relational database; but +unlike any other relational database service, Cloud Spanner scales horizontally +to hundreds or thousands of servers to handle the biggest transactional +workloads. -Be sure to activate the Cloud Spanner API on the Developer's Console to -use Cloud Spanner from your project. - `Client Library Documentation`_ - `Product Documentation`_ -.. |stable| image:: https://img.shields.io/badge/support-stable-gold.svg - :target: https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels +.. |GA| image:: https://img.shields.io/badge/support-GA-gold.svg + :target: https://github.com/googleapis/google-cloud-python/blob/main/README.rst#general-availability .. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-spanner.svg :target: https://pypi.org/project/google-cloud-spanner/ .. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-spanner.svg :target: https://pypi.org/project/google-cloud-spanner/ -.. _Cloud Spanner API: https://cloud.google.com/spanner/docs/ +.. _Cloud Spanner: https://cloud.google.com/spanner/ .. _Client Library Documentation: https://cloud.google.com/python/docs/reference/spanner/latest -.. _Product Documentation: https://cloud.google.com/spanner/docs/ +.. _Product Documentation: https://cloud.google.com/spanner/docs Quick Start ----------- @@ -31,12 +32,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ -3. `Enable the Cloud Spanner API.`_ +3. `Enable the Google Cloud Spanner API.`_ 4. `Setup Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project -.. _Enable the Cloud Spanner API.: https://cloud.google.com/spanner/docs/ +.. _Enable the Google Cloud Spanner API.: https://cloud.google.com/spanner .. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation @@ -53,25 +54,15 @@ dependencies. .. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ -Code samples and snippets -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Code samples and snippets live in the `samples/` folder. - - Supported Python Versions ^^^^^^^^^^^^^^^^^^^^^^^^^ -Our client libraries are compatible with all current [active](https://devguide.python.org/devcycle/#in-development-main-branch) and [maintenance](https://devguide.python.org/devcycle/#maintenance-branches) versions of -Python. - Python >= 3.7 -Unsupported Python Versions -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Python <= 3.6 - -If you are using an [end-of-life](https://devguide.python.org/devcycle/#end-of-life-branches) -version of Python, we recommend that you update as soon as possible to an actively supported version. +Deprecated Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^ +Python == 2.7. +Python == 3.5. +Python == 3.6. Mac/Linux @@ -95,15 +86,159 @@ Windows \Scripts\activate \Scripts\pip.exe install google-cloud-spanner + +Example Usage +------------- + + +Executing Arbitrary SQL in a Transaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generally, to work with Cloud Spanner, you will want a transaction. The +preferred mechanism for this is to create a single function, which executes +as a callback to ``database.run_in_transaction``: + +.. code:: python + + # First, define the function that represents a single "unit of work" + # that should be run within the transaction. + def update_anniversary(transaction, person_id, unix_timestamp): + # The query itself is just a string. + # + # The use of @parameters is recommended rather than doing your + # own string interpolation; this provides protections against + # SQL injection attacks. + query = """SELECT anniversary FROM people + WHERE id = @person_id""" + + # When executing the SQL statement, the query and parameters are sent + # as separate arguments. When using parameters, you must specify + # both the parameters themselves and their types. + row = transaction.execute_sql( + query=query, + params={'person_id': person_id}, + param_types={ + 'person_id': types.INT64_PARAM_TYPE, + }, + ).one() + + # Now perform an update on the data. + old_anniversary = row[0] + new_anniversary = _compute_anniversary(old_anniversary, years) + transaction.update( + 'people', + ['person_id', 'anniversary'], + [person_id, new_anniversary], + ) + + # Actually run the `update_anniversary` function in a transaction. + database.run_in_transaction(update_anniversary, + person_id=42, + unix_timestamp=1335020400, + ) + + +Select records using a Transaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once you have a transaction object (such as the first argument sent to +``run_in_transaction``), reading data is easy: + +.. code:: python + + # Define a SELECT query. + query = """SELECT e.first_name, e.last_name, p.telephone + FROM employees as e, phones as p + WHERE p.employee_id == e.employee_id""" + + # Execute the query and return results. + result = transaction.execute_sql(query) + for row in result.rows: + print(row) + + +Insert records using Data Manipulation Language (DML) with a Transaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the ``execute_update()`` method to execute a DML statement: + +.. code:: python + + spanner_client = spanner.Client() + instance = spanner_client.instance(instance_id) + database = instance.database(database_id) + + def insert_singers(transaction): + row_ct = transaction.execute_update( + "INSERT Singers (SingerId, FirstName, LastName) " + " VALUES (10, 'Virginia', 'Watson')" + ) + + print("{} record(s) inserted.".format(row_ct)) + + database.run_in_transaction(insert_singers) + + +Insert records using Mutations with a Transaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To add one or more records to a table, use ``insert``: + +.. code:: python + + transaction.insert( + 'citizens', + columns=['email', 'first_name', 'last_name', 'age'], + values=[ + ['phred@exammple.com', 'Phred', 'Phlyntstone', 32], + ['bharney@example.com', 'Bharney', 'Rhubble', 31], + ], + ) + + +Update records using Data Manipulation Language (DML) with a Transaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + spanner_client = spanner.Client() + instance = spanner_client.instance(instance_id) + database = instance.database(database_id) + + def update_albums(transaction): + row_ct = transaction.execute_update( + "UPDATE Albums " + "SET MarketingBudget = MarketingBudget * 2 " + "WHERE SingerId = 1 and AlbumId = 1" + ) + + print("{} record(s) updated.".format(row_ct)) + + database.run_in_transaction(update_albums) + + +Update records using Mutations with a Transaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Transaction.update`` updates one or more existing records in a table. Fails +if any of the records does not already exist. + +.. code:: python + + transaction.update( + 'citizens', + columns=['email', 'age'], + values=[ + ['phred@exammple.com', 33], + ['bharney@example.com', 32], + ], + ) + + Next Steps ~~~~~~~~~~ -- Read the `Client Library Documentation`_ for Cloud Spanner API - to see other available methods on the client. -- Read the `Cloud Spanner API Product documentation`_ to learn - more about the product and see How-to Guides. -- View this `README`_ to see the full list of Cloud - APIs that we cover. - -.. _Cloud Spanner API Product documentation: https://cloud.google.com/spanner/docs/ -.. _README: https://github.com/googleapis/google-cloud-python/blob/main/README.rst +- See the `Client Library Documentation`_ to learn how to connect to Cloud + Spanner using this Client Library. +- Read the `Product documentation`_ to learn + more about the product and see How-to Guides. diff --git a/owlbot.py b/owlbot.py index a3a048fffb..32bb3001fd 100644 --- a/owlbot.py +++ b/owlbot.py @@ -148,6 +148,7 @@ def get_staging_dirs( excludes=[ ".coveragerc", ".github/workflows", # exclude gh actions as credentials are needed for tests + "README.rst", ], ) From 9590f536987248ca4db06e41a2b25d6d341c376e Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Sat, 9 Jul 2022 09:58:27 +0000 Subject: [PATCH 7/9] restore manual changes to noxfile.py --- noxfile.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 50c963cd4e..2f93a4fae1 100644 --- a/noxfile.py +++ b/noxfile.py @@ -238,7 +238,8 @@ def install_systemtest_dependencies(session, *constraints): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) -def system(session): +@nox.parametrize("database_dialect", ["GOOGLE_STANDARD_SQL", "POSTGRESQL"]) +def system(session, database_dialect): """Run the system test suite.""" constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" @@ -256,6 +257,9 @@ def system(session): session.skip( "Credentials or emulator host must be set via environment variable" ) + # If POSTGRESQL tests and Emulator, skip the tests + if os.environ.get("SPANNER_EMULATOR_HOST") and database_dialect == "POSTGRESQL": + session.skip("Postgresql is not supported by Emulator yet.") # Install pyopenssl for mTLS testing. if os.environ.get("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true": @@ -277,6 +281,10 @@ def system(session): f"--junitxml=system_{session.python}_sponge_log.xml", system_test_path, *session.posargs, + env={ + "SPANNER_DATABASE_DIALECT": database_dialect, + "SKIP_BACKUP_TESTS": "true", + }, ) if system_test_folder_exists: session.run( @@ -285,6 +293,10 @@ def system(session): f"--junitxml=system_{session.python}_sponge_log.xml", system_test_folder_path, *session.posargs, + env={ + "SPANNER_DATABASE_DIALECT": database_dialect, + "SKIP_BACKUP_TESTS": "true", + }, ) From 02bb39cf094a9f744e4a77cd2b88df5d4b21b65d Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Sat, 9 Jul 2022 10:21:35 +0000 Subject: [PATCH 8/9] update owlbot.py to apply manual changes from #759 --- owlbot.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/owlbot.py b/owlbot.py index 32bb3001fd..3e85b41501 100644 --- a/owlbot.py +++ b/owlbot.py @@ -223,6 +223,9 @@ def place_before(path, text, *before_text, escape=None): session.skip( "Credentials or emulator host must be set via environment variable" ) + # If POSTGRESQL tests and Emulator, skip the tests + if os.environ.get("SPANNER_EMULATOR_HOST") and database_dialect == "POSTGRESQL": + session.skip("Postgresql is not supported by Emulator yet.") """ place_before( @@ -248,6 +251,38 @@ def place_before(path, text, *before_text, escape=None): """session.install("-e", ".[tracing]")""", ) +# Apply manual changes from PR https://github.com/googleapis/python-spanner/pull/759 +s.replace( + "noxfile.py", + """@nox.session\(python=SYSTEM_TEST_PYTHON_VERSIONS\) +def system\(session\):""", + """@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) +@nox.parametrize("database_dialect", ["GOOGLE_STANDARD_SQL", "POSTGRESQL"]) +def system(session, database_dialect):""", +) + +s.replace("noxfile.py", + """system_test_path, + \*session.posargs""", + """system_test_path, + *session.posargs, + env={ + "SPANNER_DATABASE_DIALECT": database_dialect, + "SKIP_BACKUP_TESTS": "true", + },""" +) + +s.replace("noxfile.py", + """system_test_folder_path, + \*session.posargs""", + """system_test_folder_path, + *session.posargs, + env={ + "SPANNER_DATABASE_DIALECT": database_dialect, + "SKIP_BACKUP_TESTS": "true", + },""" +) + s.replace( "noxfile.py", r"""# Install all test dependencies, then install this package into the From 821f4592d3ec62db2b3c2f7f63cafa613d6e86f5 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Sat, 9 Jul 2022 10:25:57 +0000 Subject: [PATCH 9/9] regenerate pb2 files using latest version of grpcio tools --- benchmark/benchwrapper/proto/spanner_pb2.py | 320 ++------------------ 1 file changed, 27 insertions(+), 293 deletions(-) diff --git a/benchmark/benchwrapper/proto/spanner_pb2.py b/benchmark/benchwrapper/proto/spanner_pb2.py index b469809c3d..e2d9b1a825 100644 --- a/benchmark/benchwrapper/proto/spanner_pb2.py +++ b/benchmark/benchwrapper/proto/spanner_pb2.py @@ -3,6 +3,7 @@ # source: benchmark/benchwrapper/proto/spanner.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database @@ -15,254 +16,16 @@ -DESCRIPTOR = _descriptor.FileDescriptor( - name='benchmark/benchwrapper/proto/spanner.proto', - package='spanner_bench', - syntax='proto3', - serialized_options=b'\220\001\001', - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n*benchmark/benchwrapper/proto/spanner.proto\x12\rspanner_bench\"P\n\x06Singer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x12\n\nfirst_name\x18\x02 \x01(\t\x12\x11\n\tlast_name\x18\x03 \x01(\t\x12\x13\n\x0bsinger_info\x18\x04 \x01(\t\";\n\x05\x41lbum\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x11\n\tsinger_id\x18\x02 \x01(\x03\x12\x13\n\x0b\x61lbum_title\x18\x03 \x01(\t\"\x1a\n\tReadQuery\x12\r\n\x05query\x18\x01 \x01(\t\"[\n\x0bInsertQuery\x12&\n\x07singers\x18\x01 \x03(\x0b\x32\x15.spanner_bench.Singer\x12$\n\x06\x61lbums\x18\x02 \x03(\x0b\x32\x14.spanner_bench.Album\"\x1e\n\x0bUpdateQuery\x12\x0f\n\x07queries\x18\x01 \x03(\t\"\x0f\n\rEmptyResponse2\xe3\x01\n\x13SpannerBenchWrapper\x12@\n\x04Read\x12\x18.spanner_bench.ReadQuery\x1a\x1c.spanner_bench.EmptyResponse\"\x00\x12\x44\n\x06Insert\x12\x1a.spanner_bench.InsertQuery\x1a\x1c.spanner_bench.EmptyResponse\"\x00\x12\x44\n\x06Update\x12\x1a.spanner_bench.UpdateQuery\x1a\x1c.spanner_bench.EmptyResponse\"\x00\x42\x03\x90\x01\x01\x62\x06proto3' -) +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n*benchmark/benchwrapper/proto/spanner.proto\x12\rspanner_bench\"P\n\x06Singer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x12\n\nfirst_name\x18\x02 \x01(\t\x12\x11\n\tlast_name\x18\x03 \x01(\t\x12\x13\n\x0bsinger_info\x18\x04 \x01(\t\";\n\x05\x41lbum\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x11\n\tsinger_id\x18\x02 \x01(\x03\x12\x13\n\x0b\x61lbum_title\x18\x03 \x01(\t\"\x1a\n\tReadQuery\x12\r\n\x05query\x18\x01 \x01(\t\"[\n\x0bInsertQuery\x12&\n\x07singers\x18\x01 \x03(\x0b\x32\x15.spanner_bench.Singer\x12$\n\x06\x61lbums\x18\x02 \x03(\x0b\x32\x14.spanner_bench.Album\"\x1e\n\x0bUpdateQuery\x12\x0f\n\x07queries\x18\x01 \x03(\t\"\x0f\n\rEmptyResponse2\xe3\x01\n\x13SpannerBenchWrapper\x12@\n\x04Read\x12\x18.spanner_bench.ReadQuery\x1a\x1c.spanner_bench.EmptyResponse\"\x00\x12\x44\n\x06Insert\x12\x1a.spanner_bench.InsertQuery\x1a\x1c.spanner_bench.EmptyResponse\"\x00\x12\x44\n\x06Update\x12\x1a.spanner_bench.UpdateQuery\x1a\x1c.spanner_bench.EmptyResponse\"\x00\x42\x03\x90\x01\x01\x62\x06proto3') - -_SINGER = _descriptor.Descriptor( - name='Singer', - full_name='spanner_bench.Singer', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='id', full_name='spanner_bench.Singer.id', index=0, - number=1, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='first_name', full_name='spanner_bench.Singer.first_name', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='last_name', full_name='spanner_bench.Singer.last_name', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='singer_info', full_name='spanner_bench.Singer.singer_info', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=61, - serialized_end=141, -) - - -_ALBUM = _descriptor.Descriptor( - name='Album', - full_name='spanner_bench.Album', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='id', full_name='spanner_bench.Album.id', index=0, - number=1, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='singer_id', full_name='spanner_bench.Album.singer_id', index=1, - number=2, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='album_title', full_name='spanner_bench.Album.album_title', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=143, - serialized_end=202, -) - - -_READQUERY = _descriptor.Descriptor( - name='ReadQuery', - full_name='spanner_bench.ReadQuery', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='query', full_name='spanner_bench.ReadQuery.query', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=204, - serialized_end=230, -) - - -_INSERTQUERY = _descriptor.Descriptor( - name='InsertQuery', - full_name='spanner_bench.InsertQuery', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='singers', full_name='spanner_bench.InsertQuery.singers', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='albums', full_name='spanner_bench.InsertQuery.albums', index=1, - number=2, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=232, - serialized_end=323, -) - - -_UPDATEQUERY = _descriptor.Descriptor( - name='UpdateQuery', - full_name='spanner_bench.UpdateQuery', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='queries', full_name='spanner_bench.UpdateQuery.queries', index=0, - number=1, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=325, - serialized_end=355, -) - - -_EMPTYRESPONSE = _descriptor.Descriptor( - name='EmptyResponse', - full_name='spanner_bench.EmptyResponse', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=357, - serialized_end=372, -) - -_INSERTQUERY.fields_by_name['singers'].message_type = _SINGER -_INSERTQUERY.fields_by_name['albums'].message_type = _ALBUM -DESCRIPTOR.message_types_by_name['Singer'] = _SINGER -DESCRIPTOR.message_types_by_name['Album'] = _ALBUM -DESCRIPTOR.message_types_by_name['ReadQuery'] = _READQUERY -DESCRIPTOR.message_types_by_name['InsertQuery'] = _INSERTQUERY -DESCRIPTOR.message_types_by_name['UpdateQuery'] = _UPDATEQUERY -DESCRIPTOR.message_types_by_name['EmptyResponse'] = _EMPTYRESPONSE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - +_SINGER = DESCRIPTOR.message_types_by_name['Singer'] +_ALBUM = DESCRIPTOR.message_types_by_name['Album'] +_READQUERY = DESCRIPTOR.message_types_by_name['ReadQuery'] +_INSERTQUERY = DESCRIPTOR.message_types_by_name['InsertQuery'] +_UPDATEQUERY = DESCRIPTOR.message_types_by_name['UpdateQuery'] +_EMPTYRESPONSE = DESCRIPTOR.message_types_by_name['EmptyResponse'] Singer = _reflection.GeneratedProtocolMessageType('Singer', (_message.Message,), { 'DESCRIPTOR' : _SINGER, '__module__' : 'benchmark.benchwrapper.proto.spanner_pb2' @@ -305,54 +68,25 @@ }) _sym_db.RegisterMessage(EmptyResponse) - -DESCRIPTOR._options = None - -_SPANNERBENCHWRAPPER = _descriptor.ServiceDescriptor( - name='SpannerBenchWrapper', - full_name='spanner_bench.SpannerBenchWrapper', - file=DESCRIPTOR, - index=0, - serialized_options=None, - create_key=_descriptor._internal_create_key, - serialized_start=375, - serialized_end=602, - methods=[ - _descriptor.MethodDescriptor( - name='Read', - full_name='spanner_bench.SpannerBenchWrapper.Read', - index=0, - containing_service=None, - input_type=_READQUERY, - output_type=_EMPTYRESPONSE, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name='Insert', - full_name='spanner_bench.SpannerBenchWrapper.Insert', - index=1, - containing_service=None, - input_type=_INSERTQUERY, - output_type=_EMPTYRESPONSE, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name='Update', - full_name='spanner_bench.SpannerBenchWrapper.Update', - index=2, - containing_service=None, - input_type=_UPDATEQUERY, - output_type=_EMPTYRESPONSE, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), -]) -_sym_db.RegisterServiceDescriptor(_SPANNERBENCHWRAPPER) - -DESCRIPTOR.services_by_name['SpannerBenchWrapper'] = _SPANNERBENCHWRAPPER - +_SPANNERBENCHWRAPPER = DESCRIPTOR.services_by_name['SpannerBenchWrapper'] +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = b'\220\001\001' + _SINGER._serialized_start=61 + _SINGER._serialized_end=141 + _ALBUM._serialized_start=143 + _ALBUM._serialized_end=202 + _READQUERY._serialized_start=204 + _READQUERY._serialized_end=230 + _INSERTQUERY._serialized_start=232 + _INSERTQUERY._serialized_end=323 + _UPDATEQUERY._serialized_start=325 + _UPDATEQUERY._serialized_end=355 + _EMPTYRESPONSE._serialized_start=357 + _EMPTYRESPONSE._serialized_end=372 + _SPANNERBENCHWRAPPER._serialized_start=375 + _SPANNERBENCHWRAPPER._serialized_end=602 SpannerBenchWrapper = service_reflection.GeneratedServiceType('SpannerBenchWrapper', (_service.Service,), dict( DESCRIPTOR = _SPANNERBENCHWRAPPER, __module__ = 'benchmark.benchwrapper.proto.spanner_pb2'