Skip to content

Commit

Permalink
feat: Stage 3-4 of nox implementation - adding auto-format targets (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mf2199 authored and c24t committed Sep 15, 2020
1 parent dd005d5 commit 59e7c3f
Show file tree
Hide file tree
Showing 20 changed files with 168 additions and 123 deletions.
4 changes: 1 addition & 3 deletions django_spanner/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
# expression or the result of a bilateral transformation). In those cases,
# special characters for REGEXP_CONTAINS operators (e.g. \, *, _) must be
# escaped on database side.
pattern_esc = (
r'REPLACE(REPLACE(REPLACE({}, "\\", "\\\\"), "%%", r"\%%"), "_", r"\_")'
)
pattern_esc = r'REPLACE(REPLACE(REPLACE({}, "\\", "\\\\"), "%%", r"\%%"), "_", r"\_")'
# These are all no-ops in favor of using REGEXP_CONTAINS in the customized
# lookups.
pattern_ops = {
Expand Down
8 changes: 1 addition & 7 deletions django_spanner/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,9 @@
from django.core.exceptions import EmptyResultSet
from django.db.models.sql.compiler import (
SQLAggregateCompiler as BaseSQLAggregateCompiler,
)
from django.db.models.sql.compiler import SQLCompiler as BaseSQLCompiler
from django.db.models.sql.compiler import (
SQLCompiler as BaseSQLCompiler,
SQLDeleteCompiler as BaseSQLDeleteCompiler,
)
from django.db.models.sql.compiler import (
SQLInsertCompiler as BaseSQLInsertCompiler,
)
from django.db.models.sql.compiler import (
SQLUpdateCompiler as BaseSQLUpdateCompiler,
)
from django.db.utils import DatabaseError
Expand Down
10 changes: 5 additions & 5 deletions django_spanner/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def get_relations(self, cursor, table_name):
rc.UNIQUE_CONSTRAINT_NAME = ccu.CONSTRAINT_NAME
WHERE
tc.TABLE_NAME="%s"'''
% self.connection.ops.quote_name(table_name),
% self.connection.ops.quote_name(table_name)
)
return {
column: (referred_column, referred_table)
Expand All @@ -116,7 +116,7 @@ def get_primary_key_column(self, cursor, table_name):
WHERE
tc.TABLE_NAME="%s" AND tc.CONSTRAINT_TYPE='PRIMARY KEY' AND tc.TABLE_SCHEMA=''
"""
% self.connection.ops.quote_name(table_name),
% self.connection.ops.quote_name(table_name)
)
return results[0][0] if results else None

Expand All @@ -133,7 +133,7 @@ def get_constraints(self, cursor, table_name):
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
WHERE TABLE_NAME="{table}"'''.format(
table=quoted_table_name
),
)
)
for constraint, column_name in constraint_columns:
if constraint not in constraints:
Expand All @@ -160,7 +160,7 @@ def get_constraints(self, cursor, table_name):
WHERE
TABLE_NAME="{table}"'''.format(
table=quoted_table_name
),
)
)
for constraint, constraint_type in constraint_types:
already_added = constraint in constraints
Expand Down Expand Up @@ -208,7 +208,7 @@ def get_constraints(self, cursor, table_name):
idx_col.ORDINAL_POSITION
""".format(
table=quoted_table_name
),
)
)
for (
index_name,
Expand Down
9 changes: 2 additions & 7 deletions django_spanner/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,11 @@
from django.db.utils import DatabaseError
from django.utils import timezone
from django.utils.duration import duration_microseconds

from spanner_dbapi.parse_utils import DateStr, TimestampStr, escape_name


class DatabaseOperations(BaseDatabaseOperations):
cast_data_types = {
"CharField": "STRING",
"TextField": "STRING",
}
cast_data_types = {"CharField": "STRING", "TextField": "STRING"}
cast_char_field_without_max_length = "STRING"
compiler_module = "django_spanner.compiler"
# Django's lookup names that require a different name in Spanner's
Expand Down Expand Up @@ -247,8 +243,7 @@ def datetime_cast_time_sql(self, field_name, tzname):
# TIMESTAMP to another time zone.
return (
"TIMESTAMP(FORMAT_TIMESTAMP("
"'%%Y-%%m-%%d %%R:%%E9S %%Z', %s, '%s'))"
% (field_name, tzname,)
"'%%Y-%%m-%%d %%R:%%E9S %%Z', %s, '%s'))" % (field_name, tzname)
)

def date_interval_sql(self, timedelta):
Expand Down
4 changes: 2 additions & 2 deletions django_spanner/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def create_model(self, model):
)
# Add the SQL to our big list
column_sqls.append(
"%s %s" % (self.quote_name(field.column), definition,)
"%s %s" % (self.quote_name(field.column), definition)
)
# Create a unique constraint separately because Spanner doesn't
# allow them inline on a column.
Expand Down Expand Up @@ -279,7 +279,7 @@ def _alter_field(
nullability_changed = old_field.null != new_field.null
if nullability_changed:
index_names = self._constraint_names(
model, [old_field.column], index=True,
model, [old_field.column], index=True
)
if index_names and not old_field.db_index:
raise NotSupportedError(
Expand Down
2 changes: 1 addition & 1 deletion django_spanner/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ def check_django_compatability():
raise ImproperlyConfigured(
"You must use the latest version of django-spanner {A}.{B}.x "
"with Django {A}.{B}.y (found django-spanner {C}).".format(
A=django.VERSION[0], B=django.VERSION[1], C=__version__,
A=django.VERSION[0], B=django.VERSION[1], C=__version__
)
)
5 changes: 4 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,10 @@
intersphinx_mapping = {
"python": ("http://python.readthedocs.org/en/latest/", None),
"google-auth": ("https://google-auth.readthedocs.io/en/stable", None),
"google.api_core": ("https://googleapis.dev/python/google-api-core/latest/", None),
"google.api_core": (
"https://googleapis.dev/python/google-api-core/latest/",
None,
),
"grpc": ("https://grpc.io/grpc/python/", None),
}

Expand Down
48 changes: 47 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,52 @@
import shutil


BLACK_VERSION = "black==19.10b0"
BLACK_PATHS = [
"django_spanner",
"docs",
"spanner_dbapi",
"tests",
"noxfile.py",
"setup.py",
]


@nox.session(python="3.8")
def lint(session):
"""Run linters.
Returns a failure if the linters find linting errors or sufficiently
serious code quality issues.
"""
session.install("flake8", BLACK_VERSION)
session.run("black", "--check", *BLACK_PATHS)
session.run("flake8", "django_spanner", "spanner_dbapi", "tests")


@nox.session(python="3.8")
def blacken(session):
"""Run black.
Format code to uniform standard.
This currently uses Python 3.6 due to the automated Kokoro run of synthtool.
That run uses an image that doesn't have 3.6 installed. Before updating this
check the state of the `gcp_ubuntu_config` we use for that Kokoro run.
"""
session.install(BLACK_VERSION)
session.run("black", *BLACK_PATHS)


@nox.session(python="3.8")
def lint_setup_py(session):
"""Verify that setup.py is valid (including RST check)."""
session.install("docutils", "pygments")
session.run(
"python", "setup.py", "check", "--restructuredtext", "--strict"
)


def default(session):
# Install all test dependencies, then install this package in-place.
session.install("mock", "pytest", "pytest-cov")
Expand All @@ -24,7 +70,7 @@ def default(session):
"py.test",
"--quiet",
os.path.join("tests", "spanner_dbapi"),
*session.posargs,
*session.posargs
)


Expand Down
9 changes: 9 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ ignore =
W503 # allow line breaks before binary ops
W504 # allow line breaks after binary ops
E203 # allow whitespace before ':' (https://github.com/psf/black#slices)
exclude =
# Exclude generated code.
**/_build/**

# Standard linting exemptions.
__pycache__,
.git,
*.pyc,
conf.py

[isort]
use_parentheses = True
Expand Down
57 changes: 27 additions & 30 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@
# 'Development Status :: 4 - Beta'
# 'Development Status :: 5 - Production/Stable'
release_status = "Development Status :: 3 - Alpha"
dependencies = [
'sqlparse >= 0.3.0',
'google-cloud-spanner >= 1.8.0',
]
dependencies = ["sqlparse >= 0.3.0", "google-cloud-spanner >= 1.8.0"]
extras = {}


Expand All @@ -36,30 +33,30 @@


setup(
name=name,
version=version,
description=description,
long_description=readme,
author='Google LLC',
author_email='cloud-spanner-developers@googlegroups.com',
license='BSD',
packages=find_packages(exclude=['tests']),
install_requires=dependencies,
url="https://github.com/googleapis/python-spanner-django",
classifiers=[
release_status,
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Utilities',
'Framework :: Django',
'Framework :: Django :: 2.2',
],
extras_require=extras,
python_requires=">=3.5",
name=name,
version=version,
description=description,
long_description=readme,
author="Google LLC",
author_email="cloud-spanner-developers@googlegroups.com",
license="BSD",
packages=find_packages(exclude=["tests"]),
install_requires=dependencies,
url="https://github.com/googleapis/python-spanner-django",
classifiers=[
release_status,
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Utilities",
"Framework :: Django",
"Framework :: Django :: 2.2",
],
extras_require=extras,
python_requires=">=3.5",
)
2 changes: 1 addition & 1 deletion spanner_dbapi/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def get_table_column_schema(self, table_name):
column_details = {}
for column_name, is_nullable, spanner_type in rows:
column_details[column_name] = ColumnDetails(
null_ok=is_nullable == "YES", spanner_type=spanner_type,
null_ok=is_nullable == "YES", spanner_type=spanner_type
)
return column_details

Expand Down
8 changes: 3 additions & 5 deletions spanner_dbapi/cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ def execute(self, sql, args=None):
raise OperationalError(e.details if hasattr(e, "details") else e)

def __handle_update(self, sql, params):
self._connection.in_transaction(
self.__do_execute_update, sql, params,
)
self._connection.in_transaction(self.__do_execute_update, sql, params)

def __do_execute_update(self, transaction, sql, params, param_types=None):
sql = ensure_where_clause(sql)
Expand Down Expand Up @@ -141,14 +139,14 @@ def __handle_insert(self, sql, params):
# The common case of multiple values being passed in
# non-complex pyformat args and need to be uploaded in one RPC.
return self._connection.in_transaction(
self.__do_execute_insert_homogenous, parts,
self.__do_execute_insert_homogenous, parts
)
else:
# All the other cases that are esoteric and need
# transaction.execute_sql
sql_params_list = parts.get("sql_params_list")
return self._connection.in_transaction(
self.__do_execute_insert_heterogenous, sql_params_list,
self.__do_execute_insert_heterogenous, sql_params_list
)

def __do_execute_insert_heterogenous(self, transaction, sql_params_list):
Expand Down
2 changes: 1 addition & 1 deletion spanner_dbapi/parse_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ def rows_for_insert_or_update(columns, params, pyformat_args=None):
# Now chop up the strides.
strides = []
for step in range(0, len(params), n_stride):
stride = tuple(params[step: step + n_stride:])
stride = tuple(params[step : step + n_stride :])
strides.append(stride)

return strides
Expand Down
22 changes: 16 additions & 6 deletions tests/spanner_dbapi/test_connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,26 @@ def test_connect(self):
) as client_info_mock:

connection = connect(
"test-instance", "test-database", PROJECT, CREDENTIALS, USER_AGENT
"test-instance",
"test-database",
PROJECT,
CREDENTIALS,
USER_AGENT,
)

self.assertIsInstance(connection, Connection)
client_info_mock.assert_called_once_with(USER_AGENT)

client_mock.assert_called_once_with(
project=PROJECT, credentials=CREDENTIALS, client_info=CLIENT_INFO
project=PROJECT,
credentials=CREDENTIALS,
client_info=CLIENT_INFO,
)

def test_instance_not_found(self):
with mock.patch(
"google.cloud.spanner_v1.instance.Instance.exists", return_value=False
"google.cloud.spanner_v1.instance.Instance.exists",
return_value=False,
) as exists_mock:

with self.assertRaises(ValueError):
Expand All @@ -58,10 +65,12 @@ def test_instance_not_found(self):

def test_database_not_found(self):
with mock.patch(
"google.cloud.spanner_v1.instance.Instance.exists", return_value=True
"google.cloud.spanner_v1.instance.Instance.exists",
return_value=True,
):
with mock.patch(
"google.cloud.spanner_v1.database.Database.exists", return_value=False
"google.cloud.spanner_v1.database.Database.exists",
return_value=False,
) as exists_mock:

with self.assertRaises(ValueError):
Expand All @@ -88,7 +97,8 @@ def test_connect_database_id(self):
"google.cloud.spanner_v1.instance.Instance.database"
) as database_mock:
with mock.patch(
"google.cloud.spanner_v1.instance.Instance.exists", return_value=True
"google.cloud.spanner_v1.instance.Instance.exists",
return_value=True,
):
connection = connect("test-instance", DATABASE)

Expand Down
Loading

0 comments on commit 59e7c3f

Please sign in to comment.