From 63c0f7ed4d10fc145a77fe43865194917db4f55c Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Wed, 29 Aug 2018 14:43:19 -0700 Subject: [PATCH 1/8] Added samples for using Cloud SQL with App Engine Python 3.7 Standard --- appengine/standard_python37/cloudsql/app.yaml | 9 +++ appengine/standard_python37/cloudsql/main.py | 57 ++++++++++++++ .../cloudsql/main_pooling.py | 68 ++++++++++++++++ .../cloudsql/main_postgressql.py | 57 ++++++++++++++ .../cloudsql/main_postgressql_pooling.py | 66 ++++++++++++++++ .../standard_python37/cloudsql/main_test.py | 77 +++++++++++++++++++ .../cloudsql/requirements.txt | 3 + 7 files changed, 337 insertions(+) create mode 100644 appengine/standard_python37/cloudsql/app.yaml create mode 100644 appengine/standard_python37/cloudsql/main.py create mode 100644 appengine/standard_python37/cloudsql/main_pooling.py create mode 100644 appengine/standard_python37/cloudsql/main_postgressql.py create mode 100644 appengine/standard_python37/cloudsql/main_postgressql_pooling.py create mode 100644 appengine/standard_python37/cloudsql/main_test.py create mode 100644 appengine/standard_python37/cloudsql/requirements.txt diff --git a/appengine/standard_python37/cloudsql/app.yaml b/appengine/standard_python37/cloudsql/app.yaml new file mode 100644 index 00000000000..a16f999de9a --- /dev/null +++ b/appengine/standard_python37/cloudsql/app.yaml @@ -0,0 +1,9 @@ +# [START gae_python37_cloudsql_config] +runtime: python37 + +env_variables: + CLOUDSQL_USERNAME: YOUR-USERNAME + CLOUDSQL_PASSWORD: YOUR-PASSWORD + CLOUDSQL_DATABASE_NAME: YOUR-DATABASE + CLOUDSQL_CONNECTION_NAME: YOUR-CONNECTION-NAME +# [END gae_python37_cloudsql_config] diff --git a/appengine/standard_python37/cloudsql/main.py b/appengine/standard_python37/cloudsql/main.py new file mode 100644 index 00000000000..c9a0d1a8b5f --- /dev/null +++ b/appengine/standard_python37/cloudsql/main.py @@ -0,0 +1,57 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START gae_python37_cloudsql_mysql] +import os + +from flask import Flask +import mysql.connector + +db_user = os.environ.get('CLOUDSQL_USERNAME') +db_password = os.environ.get('CLOUDSQL_PASSWORD') +db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') + +app = Flask(__name__) + + +@app.route('/') +def main(): + # When deployed to App Engine, the `GAE_ENV` environment variable will be + # set to `standard` + if os.environ.get('GAE_ENV'): + # If deployed, use the local socket interface for accessing Cloud SQL + host = f'/cloudsql/{db_connection_name}' + else: + # If running locally, use the TCP connections instead + # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy) + # so that your application can use 127.0.0.1:3306 to connect to your + # Cloud SQL instance + host = '127.0.0.1' + + cnx = mysql.connector.connect(user=db_user, password=db_password, + host=host, database=db_name) + cursor = cnx.cursor() + cursor.execute('SELECT NOW() as now;') + result = cursor.fetchall() + current_time = result[0][0] + cursor.close() + cnx.close() + + return str(current_time) +# [END gae_python37_cloudsql_mysql] + + +if __name__ == '__main__': + app.run(host='127.0.0.1', port=8080, debug=True) diff --git a/appengine/standard_python37/cloudsql/main_pooling.py b/appengine/standard_python37/cloudsql/main_pooling.py new file mode 100644 index 00000000000..b83a407d792 --- /dev/null +++ b/appengine/standard_python37/cloudsql/main_pooling.py @@ -0,0 +1,68 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START gae_python37_cloudsql_mysql_pooling] +import os + +from flask import Flask +import mysql.connector.pooling + +db_user = os.environ.get('CLOUDSQL_USERNAME') +db_password = os.environ.get('CLOUDSQL_PASSWORD') +db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') + +# When deployed to App Engine, the `GAE_ENV` environment variable will be +# set to `standard` +if os.environ.get('GAE_ENV'): + # If deployed, use the local socket interface for accessing Cloud SQL + host = f'/cloudsql/{db_connection_name}' +else: + # If running locally, use the TCP connections instead + # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy) + # so that your application can use 127.0.0.1:3306 to connect to your + # Cloud SQL instance + host = '127.0.0.1' + +db_config = { + 'user': db_user, + 'password': db_password, + 'database': db_name, + 'host': host +} + +cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name='cnxpool', + pool_size=3, **db_config) + +app = Flask(__name__) + + +@app.route('/') +def main(): + cnx = cnxpool.get_connection() + cursor = cnx.cursor() + cursor.execute('SELECT NOW() as now;') + result = cursor.fetchall() + current_time = result[0][0] + cursor.close() + # If the connection comes from a pool, close() will send the connection + # back to the pool instead of closing it + cnx.close() + + return str(current_time) +# [END gae_python37_cloudsql_mysql_pooling] + + +if __name__ == '__main__': + app.run(host='127.0.0.1', port=8080, debug=True) diff --git a/appengine/standard_python37/cloudsql/main_postgressql.py b/appengine/standard_python37/cloudsql/main_postgressql.py new file mode 100644 index 00000000000..caec641e592 --- /dev/null +++ b/appengine/standard_python37/cloudsql/main_postgressql.py @@ -0,0 +1,57 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START gae_python37_cloudsql_psql] +import os + +from flask import Flask +import psycopg2 + +db_user = os.environ.get('CLOUDSQL_USERNAME') +db_password = os.environ.get('CLOUDSQL_PASSWORD') +db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') + +app = Flask(__name__) + + +@app.route('/') +def main(): + # When deployed to App Engine, the `GAE_ENV` environment variable will be + # set to `standard` + if os.environ.get('GAE_ENV'): + # If deployed, use the local socket interface for accessing Cloud SQL + host = f'/cloudsql/{db_connection_name}' + else: + # If running locally, use the TCP connections instead + # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy) + # so that your application can use 127.0.0.1:3306 to connect to your + # Cloud SQL instance + host = '127.0.0.1' + + cnx = psycopg2.connect(dbname=db_name, user=db_user, + password=db_password, host=host) + with cnx.cursor() as cursor: + cursor.execute('SELECT NOW() as now;') + result = cursor.fetchall() + current_time = result[0][0] + cnx.commit() + cnx.close() + + return str(current_time) +# [END gae_python37_cloudsql_psql] + + +if __name__ == '__main__': + app.run(host='127.0.0.1', port=8080, debug=True) diff --git a/appengine/standard_python37/cloudsql/main_postgressql_pooling.py b/appengine/standard_python37/cloudsql/main_postgressql_pooling.py new file mode 100644 index 00000000000..7ce7c876c1c --- /dev/null +++ b/appengine/standard_python37/cloudsql/main_postgressql_pooling.py @@ -0,0 +1,66 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START gae_python37_cloudsql_psql] +import os + +from flask import Flask +import psycopg2.pool + +db_user = os.environ.get('CLOUDSQL_USERNAME') +db_password = os.environ.get('CLOUDSQL_PASSWORD') +db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') + +# When deployed to App Engine, the `GAE_ENV` environment variable will be +# set to `standard` +if os.environ.get('GAE_ENV'): + # If deployed, use the local socket interface for accessing Cloud SQL + host = f'/cloudsql/{db_connection_name}' +else: + # If running locally, use the TCP connections instead + # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy) + # so that your application can use 127.0.0.1:3306 to connect to your + # Cloud SQL instance + host = '127.0.0.1' + +db_config = { + 'user': db_user, + 'password': db_password, + 'database': db_name, + 'host': host +} + +cnxpool = psycopg2.pool.ThreadedConnectionPool(minconn=1, maxconn=3, + **db_config) + +app = Flask(__name__) + + +@app.route('/') +def main(): + cnx = cnxpool.getconn() + with cnx.cursor() as cursor: + cursor.execute('SELECT NOW() as now;') + result = cursor.fetchall() + current_time = result[0][0] + cnx.commit() + cnxpool.putconn(cnx) + + return str(current_time) +# [END gae_python37_cloudsql_psql] + + +if __name__ == '__main__': + app.run(host='127.0.0.1', port=8080, debug=True) diff --git a/appengine/standard_python37/cloudsql/main_test.py b/appengine/standard_python37/cloudsql/main_test.py new file mode 100644 index 00000000000..df460fb24bc --- /dev/null +++ b/appengine/standard_python37/cloudsql/main_test.py @@ -0,0 +1,77 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from unittest.mock import MagicMock + +import mysql.connector.pooling +import psycopg2.pool + + +def test_main(): + import main + main.mysql.connector = MagicMock() + main.mysql.connector.connect().cursor().fetchall.return_value = [['0']] + + main.app.testing = True + client = main.app.test_client() + + r = client.get('/') + assert r.status_code == 200 + assert '0' in r.data.decode('utf-8') + + +def test_main_pooling(): + mysql.connector.pooling.MySQLConnectionPool = MagicMock() + + import main_pooling + + mock_pool = main_pooling.mysql.connector.pooling.MySQLConnectionPool() + mock_pool.get_connection().cursor().fetchall.return_value = [['0']] + + main_pooling.app.testing = True + client = main_pooling.app.test_client() + + r = client.get('/') + assert r.status_code == 200 + assert '0' in r.data.decode('utf-8') + + +def test_main_postgressql(): + import main_postgressql + main_postgressql.psycopg2.connect = MagicMock() + mock_cursor = main_postgressql.psycopg2.connect().cursor() + mock_cursor.__enter__().fetchall.return_value = [['0']] + + main_postgressql.app.testing = True + client = main_postgressql.app.test_client() + + r = client.get('/') + assert r.status_code == 200 + assert '0' in r.data.decode('utf-8') + + +def test_main_postgressql_pooling(): + psycopg2.pool.ThreadedConnectionPool = MagicMock() + + import main_postgressql_pooling + + mock_pool = main_postgressql_pooling.psycopg2.pool.ThreadedConnectionPool() + mock_pool.getconn().cursor().__enter__().fetchall.return_value = [['0']] + + main_postgressql_pooling.app.testing = True + client = main_postgressql_pooling.app.test_client() + + r = client.get('/') + assert r.status_code == 200 + assert '0' in r.data.decode('utf-8') diff --git a/appengine/standard_python37/cloudsql/requirements.txt b/appengine/standard_python37/cloudsql/requirements.txt new file mode 100644 index 00000000000..c20cd67514f --- /dev/null +++ b/appengine/standard_python37/cloudsql/requirements.txt @@ -0,0 +1,3 @@ +psycopg2==2.7.5 +psycopg2-binary==2.7.5 +mysql-connector-python==8.0.12 \ No newline at end of file From 93c382d81b392d22f89978672f709a5c29b0b10c Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Wed, 29 Aug 2018 15:10:55 -0700 Subject: [PATCH 2/8] Minor fix --- .../standard_python37/cloudsql/main_postgressql_pooling.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appengine/standard_python37/cloudsql/main_postgressql_pooling.py b/appengine/standard_python37/cloudsql/main_postgressql_pooling.py index 7ce7c876c1c..1beac4bc2f7 100644 --- a/appengine/standard_python37/cloudsql/main_postgressql_pooling.py +++ b/appengine/standard_python37/cloudsql/main_postgressql_pooling.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# [START gae_python37_cloudsql_psql] +# [START gae_python37_cloudsql_psql_pooling] import os from flask import Flask @@ -59,7 +59,7 @@ def main(): cnxpool.putconn(cnx) return str(current_time) -# [END gae_python37_cloudsql_psql] +# [END gae_python37_cloudsql_psql_pooling] if __name__ == '__main__': From 4dfb60044babf507efae4887ca8b387ab9e25499 Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Mon, 17 Sep 2018 13:47:04 -0700 Subject: [PATCH 3/8] Minor fixes. --- .../standard_python37/cloudsql/{main.py => main_mysql.py} | 8 ++++---- .../cloudsql/{main_pooling.py => main_mysql_pooling.py} | 8 ++++---- appengine/standard_python37/cloudsql/main_postgressql.py | 8 ++++---- .../cloudsql/main_postgressql_pooling.py | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) rename appengine/standard_python37/cloudsql/{main.py => main_mysql.py} (88%) rename appengine/standard_python37/cloudsql/{main_pooling.py => main_mysql_pooling.py} (90%) diff --git a/appengine/standard_python37/cloudsql/main.py b/appengine/standard_python37/cloudsql/main_mysql.py similarity index 88% rename from appengine/standard_python37/cloudsql/main.py rename to appengine/standard_python37/cloudsql/main_mysql.py index c9a0d1a8b5f..a5cebcc21c2 100644 --- a/appengine/standard_python37/cloudsql/main.py +++ b/appengine/standard_python37/cloudsql/main_mysql.py @@ -18,10 +18,10 @@ from flask import Flask import mysql.connector -db_user = os.environ.get('CLOUDSQL_USERNAME') -db_password = os.environ.get('CLOUDSQL_PASSWORD') -db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') -db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') +db_user = os.environ.get('CLOUD_SQL_USERNAME') +db_password = os.environ.get('CLOUD_SQL_PASSWORD') +db_name = os.environ.get('CLOUD_SQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUD_SQL_CONNECTION_NAME') app = Flask(__name__) diff --git a/appengine/standard_python37/cloudsql/main_pooling.py b/appengine/standard_python37/cloudsql/main_mysql_pooling.py similarity index 90% rename from appengine/standard_python37/cloudsql/main_pooling.py rename to appengine/standard_python37/cloudsql/main_mysql_pooling.py index b83a407d792..6e28971271b 100644 --- a/appengine/standard_python37/cloudsql/main_pooling.py +++ b/appengine/standard_python37/cloudsql/main_mysql_pooling.py @@ -18,10 +18,10 @@ from flask import Flask import mysql.connector.pooling -db_user = os.environ.get('CLOUDSQL_USERNAME') -db_password = os.environ.get('CLOUDSQL_PASSWORD') -db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') -db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') +db_user = os.environ.get('CLOUD_SQL_USERNAME') +db_password = os.environ.get('CLOUD_SQL_PASSWORD') +db_name = os.environ.get('CLOUD_SQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUD_SQL_CONNECTION_NAME') # When deployed to App Engine, the `GAE_ENV` environment variable will be # set to `standard` diff --git a/appengine/standard_python37/cloudsql/main_postgressql.py b/appengine/standard_python37/cloudsql/main_postgressql.py index caec641e592..10ecf650acf 100644 --- a/appengine/standard_python37/cloudsql/main_postgressql.py +++ b/appengine/standard_python37/cloudsql/main_postgressql.py @@ -18,10 +18,10 @@ from flask import Flask import psycopg2 -db_user = os.environ.get('CLOUDSQL_USERNAME') -db_password = os.environ.get('CLOUDSQL_PASSWORD') -db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') -db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') +db_user = os.environ.get('CLOUD_SQL_USERNAME') +db_password = os.environ.get('CLOUD_SQL_PASSWORD') +db_name = os.environ.get('CLOUD_SQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUD_SQL_CONNECTION_NAME') app = Flask(__name__) diff --git a/appengine/standard_python37/cloudsql/main_postgressql_pooling.py b/appengine/standard_python37/cloudsql/main_postgressql_pooling.py index 1beac4bc2f7..47c067829ed 100644 --- a/appengine/standard_python37/cloudsql/main_postgressql_pooling.py +++ b/appengine/standard_python37/cloudsql/main_postgressql_pooling.py @@ -18,10 +18,10 @@ from flask import Flask import psycopg2.pool -db_user = os.environ.get('CLOUDSQL_USERNAME') -db_password = os.environ.get('CLOUDSQL_PASSWORD') -db_name = os.environ.get('CLOUDSQL_DATABASE_NAME') -db_connection_name = os.environ.get('CLOUDSQL_CONNECTION_NAME') +db_user = os.environ.get('CLOUD_SQL_USERNAME') +db_password = os.environ.get('CLOUD_SQL_PASSWORD') +db_name = os.environ.get('CLOUD_SQL_DATABASE_NAME') +db_connection_name = os.environ.get('CLOUD_SQL_CONNECTION_NAME') # When deployed to App Engine, the `GAE_ENV` environment variable will be # set to `standard` From e3f09e31026a39a41fe70c1e37adf928d3dd530e Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Mon, 17 Sep 2018 14:28:57 -0700 Subject: [PATCH 4/8] Minor fixes. --- .../cloudsql/{main_postgressql.py => main_postgres.py} | 0 .../{main_postgressql_pooling.py => main_postgres_pooling.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename appengine/standard_python37/cloudsql/{main_postgressql.py => main_postgres.py} (100%) rename appengine/standard_python37/cloudsql/{main_postgressql_pooling.py => main_postgres_pooling.py} (100%) diff --git a/appengine/standard_python37/cloudsql/main_postgressql.py b/appengine/standard_python37/cloudsql/main_postgres.py similarity index 100% rename from appengine/standard_python37/cloudsql/main_postgressql.py rename to appengine/standard_python37/cloudsql/main_postgres.py diff --git a/appengine/standard_python37/cloudsql/main_postgressql_pooling.py b/appengine/standard_python37/cloudsql/main_postgres_pooling.py similarity index 100% rename from appengine/standard_python37/cloudsql/main_postgressql_pooling.py rename to appengine/standard_python37/cloudsql/main_postgres_pooling.py From 2cf1fd8eb7b304bfc34265f8ef9f396c4e017df1 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Wed, 10 Oct 2018 15:33:09 -0700 Subject: [PATCH 5/8] Minor fix. --- .../standard_python37/cloudsql/main_test.py | 36 +++++++++---------- .../cloudsql/requirements.txt | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/appengine/standard_python37/cloudsql/main_test.py b/appengine/standard_python37/cloudsql/main_test.py index df460fb24bc..e12215ac1a5 100644 --- a/appengine/standard_python37/cloudsql/main_test.py +++ b/appengine/standard_python37/cloudsql/main_test.py @@ -19,12 +19,12 @@ def test_main(): - import main - main.mysql.connector = MagicMock() - main.mysql.connector.connect().cursor().fetchall.return_value = [['0']] + import main_mysql + main_mysql.mysql.connector = MagicMock() + main_mysql.mysql.connector.connect().cursor().fetchall.return_value = [['0']] - main.app.testing = True - client = main.app.test_client() + main_mysql.app.testing = True + client = main_mysql.app.test_client() r = client.get('/') assert r.status_code == 200 @@ -34,13 +34,13 @@ def test_main(): def test_main_pooling(): mysql.connector.pooling.MySQLConnectionPool = MagicMock() - import main_pooling + import main_mysql_pooling - mock_pool = main_pooling.mysql.connector.pooling.MySQLConnectionPool() + mock_pool = main_mysql_pooling.mysql.connector.pooling.MySQLConnectionPool() mock_pool.get_connection().cursor().fetchall.return_value = [['0']] - main_pooling.app.testing = True - client = main_pooling.app.test_client() + main_mysql_pooling.app.testing = True + client = main_mysql_pooling.app.test_client() r = client.get('/') assert r.status_code == 200 @@ -48,13 +48,13 @@ def test_main_pooling(): def test_main_postgressql(): - import main_postgressql - main_postgressql.psycopg2.connect = MagicMock() - mock_cursor = main_postgressql.psycopg2.connect().cursor() + import main_postgres + main_postgres.psycopg2.connect = MagicMock() + mock_cursor = main_postgres.psycopg2.connect().cursor() mock_cursor.__enter__().fetchall.return_value = [['0']] - main_postgressql.app.testing = True - client = main_postgressql.app.test_client() + main_postgres.app.testing = True + client = main_postgres.app.test_client() r = client.get('/') assert r.status_code == 200 @@ -64,13 +64,13 @@ def test_main_postgressql(): def test_main_postgressql_pooling(): psycopg2.pool.ThreadedConnectionPool = MagicMock() - import main_postgressql_pooling + import main_postgres_pooling - mock_pool = main_postgressql_pooling.psycopg2.pool.ThreadedConnectionPool() + mock_pool = main_postgres_pooling.psycopg2.pool.ThreadedConnectionPool() mock_pool.getconn().cursor().__enter__().fetchall.return_value = [['0']] - main_postgressql_pooling.app.testing = True - client = main_postgressql_pooling.app.test_client() + main_postgres_pooling.app.testing = True + client =main_postgres_pooling.app.test_client() r = client.get('/') assert r.status_code == 200 diff --git a/appengine/standard_python37/cloudsql/requirements.txt b/appengine/standard_python37/cloudsql/requirements.txt index c20cd67514f..29d2385a3cb 100644 --- a/appengine/standard_python37/cloudsql/requirements.txt +++ b/appengine/standard_python37/cloudsql/requirements.txt @@ -1,3 +1,3 @@ psycopg2==2.7.5 psycopg2-binary==2.7.5 -mysql-connector-python==8.0.12 \ No newline at end of file +mysql-connector==2.1.6 \ No newline at end of file From e1836ca8fa4dd09ed35c4cb9335045a2a69b260b Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Wed, 10 Oct 2018 16:06:49 -0700 Subject: [PATCH 6/8] Updated sample to use PyMySQL + SQLAlchemy. --- .../standard_python37/cloudsql/main_mysql.py | 15 ++++++------ .../cloudsql/main_mysql_pooling.py | 23 ++++++++----------- .../standard_python37/cloudsql/main_test.py | 11 ++++----- .../cloudsql/requirements.txt | 3 ++- 4 files changed, 23 insertions(+), 29 deletions(-) diff --git a/appengine/standard_python37/cloudsql/main_mysql.py b/appengine/standard_python37/cloudsql/main_mysql.py index a5cebcc21c2..133036c2e76 100644 --- a/appengine/standard_python37/cloudsql/main_mysql.py +++ b/appengine/standard_python37/cloudsql/main_mysql.py @@ -16,7 +16,7 @@ import os from flask import Flask -import mysql.connector +import pymysql db_user = os.environ.get('CLOUD_SQL_USERNAME') db_password = os.environ.get('CLOUD_SQL_PASSWORD') @@ -40,13 +40,12 @@ def main(): # Cloud SQL instance host = '127.0.0.1' - cnx = mysql.connector.connect(user=db_user, password=db_password, - host=host, database=db_name) - cursor = cnx.cursor() - cursor.execute('SELECT NOW() as now;') - result = cursor.fetchall() - current_time = result[0][0] - cursor.close() + cnx = pymysql.connect(user=db_user, password=db_password, + host=host, db=db_name) + with cnx.cursor() as cursor: + cursor.execute('SELECT NOW() as now;') + result = cursor.fetchall() + current_time = result[0][0] cnx.close() return str(current_time) diff --git a/appengine/standard_python37/cloudsql/main_mysql_pooling.py b/appengine/standard_python37/cloudsql/main_mysql_pooling.py index 6e28971271b..3d4674ec650 100644 --- a/appengine/standard_python37/cloudsql/main_mysql_pooling.py +++ b/appengine/standard_python37/cloudsql/main_mysql_pooling.py @@ -16,7 +16,7 @@ import os from flask import Flask -import mysql.connector.pooling +import sqlalchemy db_user = os.environ.get('CLOUD_SQL_USERNAME') db_password = os.environ.get('CLOUD_SQL_PASSWORD') @@ -35,27 +35,22 @@ # Cloud SQL instance host = '127.0.0.1' -db_config = { - 'user': db_user, - 'password': db_password, - 'database': db_name, - 'host': host -} - -cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name='cnxpool', - pool_size=3, **db_config) +# The Engine object returned by create_engine() has a QueuePool integrated +# See https://docs.sqlalchemy.org/en/latest/core/pooling.html for more +# information +engine = sqlalchemy.create_engine('mysql+pymysql://{}:{}@{}/{}'.format( + db_user, db_password, host, db_name +), pool_size = 3) app = Flask(__name__) @app.route('/') def main(): - cnx = cnxpool.get_connection() - cursor = cnx.cursor() - cursor.execute('SELECT NOW() as now;') + cnx = engine.connect() + cursor = cnx.execute('SELECT NOW() as now;') result = cursor.fetchall() current_time = result[0][0] - cursor.close() # If the connection comes from a pool, close() will send the connection # back to the pool instead of closing it cnx.close() diff --git a/appengine/standard_python37/cloudsql/main_test.py b/appengine/standard_python37/cloudsql/main_test.py index e12215ac1a5..d84ec083812 100644 --- a/appengine/standard_python37/cloudsql/main_test.py +++ b/appengine/standard_python37/cloudsql/main_test.py @@ -14,14 +14,14 @@ from unittest.mock import MagicMock -import mysql.connector.pooling +import sqlalchemy import psycopg2.pool def test_main(): import main_mysql - main_mysql.mysql.connector = MagicMock() - main_mysql.mysql.connector.connect().cursor().fetchall.return_value = [['0']] + main_mysql.pymysql = MagicMock() + main_mysql.pymysql.connect().cursor().__enter__().fetchall.return_value = [['0']] main_mysql.app.testing = True client = main_mysql.app.test_client() @@ -32,12 +32,11 @@ def test_main(): def test_main_pooling(): - mysql.connector.pooling.MySQLConnectionPool = MagicMock() + sqlalchemy.create_engine = MagicMock() import main_mysql_pooling - mock_pool = main_mysql_pooling.mysql.connector.pooling.MySQLConnectionPool() - mock_pool.get_connection().cursor().fetchall.return_value = [['0']] + main_mysql_pooling.sqlalchemy.create_engine().connect().execute().fetchall.return_value = [['0']] main_mysql_pooling.app.testing = True client = main_mysql_pooling.app.test_client() diff --git a/appengine/standard_python37/cloudsql/requirements.txt b/appengine/standard_python37/cloudsql/requirements.txt index 29d2385a3cb..26288710401 100644 --- a/appengine/standard_python37/cloudsql/requirements.txt +++ b/appengine/standard_python37/cloudsql/requirements.txt @@ -1,3 +1,4 @@ psycopg2==2.7.5 psycopg2-binary==2.7.5 -mysql-connector==2.1.6 \ No newline at end of file +PyMySQL==0.9.2 +SQLAlchemy==1.2.12 \ No newline at end of file From 76a874240abad9354eca59fe7c728b14b9f01d1c Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Wed, 10 Oct 2018 16:18:09 -0700 Subject: [PATCH 7/8] Minor fix. --- .../standard_python37/cloudsql/main_mysql_pooling.py | 2 +- appengine/standard_python37/cloudsql/main_test.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/appengine/standard_python37/cloudsql/main_mysql_pooling.py b/appengine/standard_python37/cloudsql/main_mysql_pooling.py index 3d4674ec650..b8529bf9277 100644 --- a/appengine/standard_python37/cloudsql/main_mysql_pooling.py +++ b/appengine/standard_python37/cloudsql/main_mysql_pooling.py @@ -40,7 +40,7 @@ # information engine = sqlalchemy.create_engine('mysql+pymysql://{}:{}@{}/{}'.format( db_user, db_password, host, db_name -), pool_size = 3) +), pool_size=3) app = Flask(__name__) diff --git a/appengine/standard_python37/cloudsql/main_test.py b/appengine/standard_python37/cloudsql/main_test.py index d84ec083812..e9496692e6a 100644 --- a/appengine/standard_python37/cloudsql/main_test.py +++ b/appengine/standard_python37/cloudsql/main_test.py @@ -14,14 +14,15 @@ from unittest.mock import MagicMock -import sqlalchemy import psycopg2.pool +import sqlalchemy def test_main(): import main_mysql main_mysql.pymysql = MagicMock() - main_mysql.pymysql.connect().cursor().__enter__().fetchall.return_value = [['0']] + fetchall_mock = main_mysql.pymysql.connect().cursor().__enter__().fetchall + fetchall_mock.return_value = [['0']] main_mysql.app.testing = True client = main_mysql.app.test_client() @@ -36,7 +37,8 @@ def test_main_pooling(): import main_mysql_pooling - main_mysql_pooling.sqlalchemy.create_engine().connect().execute().fetchall.return_value = [['0']] + cnx_mock = main_mysql_pooling.sqlalchemy.create_engine().connect() + cnx_mock.execute().fetchall.return_value = [['0']] main_mysql_pooling.app.testing = True client = main_mysql_pooling.app.test_client() @@ -69,7 +71,7 @@ def test_main_postgressql_pooling(): mock_pool.getconn().cursor().__enter__().fetchall.return_value = [['0']] main_postgres_pooling.app.testing = True - client =main_postgres_pooling.app.test_client() + client = main_postgres_pooling.app.test_client() r = client.get('/') assert r.status_code == 200 From 5d05163e18652acc17f978f5b9796ba67c73beae Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Wed, 10 Oct 2018 16:24:59 -0700 Subject: [PATCH 8/8] Minor fix: remove F-strings --- appengine/standard_python37/cloudsql/main_mysql.py | 2 +- appengine/standard_python37/cloudsql/main_mysql_pooling.py | 2 +- appengine/standard_python37/cloudsql/main_postgres.py | 2 +- appengine/standard_python37/cloudsql/main_postgres_pooling.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appengine/standard_python37/cloudsql/main_mysql.py b/appengine/standard_python37/cloudsql/main_mysql.py index 133036c2e76..7f0082c9db3 100644 --- a/appengine/standard_python37/cloudsql/main_mysql.py +++ b/appengine/standard_python37/cloudsql/main_mysql.py @@ -32,7 +32,7 @@ def main(): # set to `standard` if os.environ.get('GAE_ENV'): # If deployed, use the local socket interface for accessing Cloud SQL - host = f'/cloudsql/{db_connection_name}' + host = '/cloudsql/{}'.format(db_connection_name) else: # If running locally, use the TCP connections instead # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy) diff --git a/appengine/standard_python37/cloudsql/main_mysql_pooling.py b/appengine/standard_python37/cloudsql/main_mysql_pooling.py index b8529bf9277..6002eb9fb8a 100644 --- a/appengine/standard_python37/cloudsql/main_mysql_pooling.py +++ b/appengine/standard_python37/cloudsql/main_mysql_pooling.py @@ -27,7 +27,7 @@ # set to `standard` if os.environ.get('GAE_ENV'): # If deployed, use the local socket interface for accessing Cloud SQL - host = f'/cloudsql/{db_connection_name}' + host = '/cloudsql/{}'.format(db_connection_name) else: # If running locally, use the TCP connections instead # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy) diff --git a/appengine/standard_python37/cloudsql/main_postgres.py b/appengine/standard_python37/cloudsql/main_postgres.py index 10ecf650acf..91c66373136 100644 --- a/appengine/standard_python37/cloudsql/main_postgres.py +++ b/appengine/standard_python37/cloudsql/main_postgres.py @@ -32,7 +32,7 @@ def main(): # set to `standard` if os.environ.get('GAE_ENV'): # If deployed, use the local socket interface for accessing Cloud SQL - host = f'/cloudsql/{db_connection_name}' + host = '/cloudsql/{}'.format(db_connection_name) else: # If running locally, use the TCP connections instead # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy) diff --git a/appengine/standard_python37/cloudsql/main_postgres_pooling.py b/appengine/standard_python37/cloudsql/main_postgres_pooling.py index 47c067829ed..b1e85de862f 100644 --- a/appengine/standard_python37/cloudsql/main_postgres_pooling.py +++ b/appengine/standard_python37/cloudsql/main_postgres_pooling.py @@ -27,7 +27,7 @@ # set to `standard` if os.environ.get('GAE_ENV'): # If deployed, use the local socket interface for accessing Cloud SQL - host = f'/cloudsql/{db_connection_name}' + host = '/cloudsql/{}'.format(db_connection_name) else: # If running locally, use the TCP connections instead # Set up Cloud SQL Proxy (cloud.google.com/sql/docs/mysql/sql-proxy)