Skip to content

Commit 7a1f6a6

Browse files
authored
feat: Stage 3-4 of nox implementation - adding auto-format targets (#478)
1 parent 144bdc2 commit 7a1f6a6

20 files changed

+168
-123
lines changed

django_spanner/base.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
8181
# expression or the result of a bilateral transformation). In those cases,
8282
# special characters for REGEXP_CONTAINS operators (e.g. \, *, _) must be
8383
# escaped on database side.
84-
pattern_esc = (
85-
r'REPLACE(REPLACE(REPLACE({}, "\\", "\\\\"), "%%", r"\%%"), "_", r"\_")'
86-
)
84+
pattern_esc = r'REPLACE(REPLACE(REPLACE({}, "\\", "\\\\"), "%%", r"\%%"), "_", r"\_")'
8785
# These are all no-ops in favor of using REGEXP_CONTAINS in the customized
8886
# lookups.
8987
pattern_ops = {

django_spanner/compiler.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,9 @@
77
from django.core.exceptions import EmptyResultSet
88
from django.db.models.sql.compiler import (
99
SQLAggregateCompiler as BaseSQLAggregateCompiler,
10-
)
11-
from django.db.models.sql.compiler import SQLCompiler as BaseSQLCompiler
12-
from django.db.models.sql.compiler import (
10+
SQLCompiler as BaseSQLCompiler,
1311
SQLDeleteCompiler as BaseSQLDeleteCompiler,
14-
)
15-
from django.db.models.sql.compiler import (
1612
SQLInsertCompiler as BaseSQLInsertCompiler,
17-
)
18-
from django.db.models.sql.compiler import (
1913
SQLUpdateCompiler as BaseSQLUpdateCompiler,
2014
)
2115
from django.db.utils import DatabaseError

django_spanner/introspection.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def get_relations(self, cursor, table_name):
9595
rc.UNIQUE_CONSTRAINT_NAME = ccu.CONSTRAINT_NAME
9696
WHERE
9797
tc.TABLE_NAME="%s"'''
98-
% self.connection.ops.quote_name(table_name),
98+
% self.connection.ops.quote_name(table_name)
9999
)
100100
return {
101101
column: (referred_column, referred_table)
@@ -116,7 +116,7 @@ def get_primary_key_column(self, cursor, table_name):
116116
WHERE
117117
tc.TABLE_NAME="%s" AND tc.CONSTRAINT_TYPE='PRIMARY KEY' AND tc.TABLE_SCHEMA=''
118118
"""
119-
% self.connection.ops.quote_name(table_name),
119+
% self.connection.ops.quote_name(table_name)
120120
)
121121
return results[0][0] if results else None
122122

@@ -133,7 +133,7 @@ def get_constraints(self, cursor, table_name):
133133
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
134134
WHERE TABLE_NAME="{table}"'''.format(
135135
table=quoted_table_name
136-
),
136+
)
137137
)
138138
for constraint, column_name in constraint_columns:
139139
if constraint not in constraints:
@@ -160,7 +160,7 @@ def get_constraints(self, cursor, table_name):
160160
WHERE
161161
TABLE_NAME="{table}"'''.format(
162162
table=quoted_table_name
163-
),
163+
)
164164
)
165165
for constraint, constraint_type in constraint_types:
166166
already_added = constraint in constraints
@@ -208,7 +208,7 @@ def get_constraints(self, cursor, table_name):
208208
idx_col.ORDINAL_POSITION
209209
""".format(
210210
table=quoted_table_name
211-
),
211+
)
212212
)
213213
for (
214214
index_name,

django_spanner/operations.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,11 @@
1616
from django.db.utils import DatabaseError
1717
from django.utils import timezone
1818
from django.utils.duration import duration_microseconds
19-
2019
from spanner_dbapi.parse_utils import DateStr, TimestampStr, escape_name
2120

2221

2322
class DatabaseOperations(BaseDatabaseOperations):
24-
cast_data_types = {
25-
"CharField": "STRING",
26-
"TextField": "STRING",
27-
}
23+
cast_data_types = {"CharField": "STRING", "TextField": "STRING"}
2824
cast_char_field_without_max_length = "STRING"
2925
compiler_module = "django_spanner.compiler"
3026
# Django's lookup names that require a different name in Spanner's
@@ -247,8 +243,7 @@ def datetime_cast_time_sql(self, field_name, tzname):
247243
# TIMESTAMP to another time zone.
248244
return (
249245
"TIMESTAMP(FORMAT_TIMESTAMP("
250-
"'%%Y-%%m-%%d %%R:%%E9S %%Z', %s, '%s'))"
251-
% (field_name, tzname,)
246+
"'%%Y-%%m-%%d %%R:%%E9S %%Z', %s, '%s'))" % (field_name, tzname)
252247
)
253248

254249
def date_interval_sql(self, timedelta):

django_spanner/schema.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def create_model(self, model):
7575
)
7676
# Add the SQL to our big list
7777
column_sqls.append(
78-
"%s %s" % (self.quote_name(field.column), definition,)
78+
"%s %s" % (self.quote_name(field.column), definition)
7979
)
8080
# Create a unique constraint separately because Spanner doesn't
8181
# allow them inline on a column.
@@ -279,7 +279,7 @@ def _alter_field(
279279
nullability_changed = old_field.null != new_field.null
280280
if nullability_changed:
281281
index_names = self._constraint_names(
282-
model, [old_field.column], index=True,
282+
model, [old_field.column], index=True
283283
)
284284
if index_names and not old_field.db_index:
285285
raise NotSupportedError(

django_spanner/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ def check_django_compatability():
1515
raise ImproperlyConfigured(
1616
"You must use the latest version of django-spanner {A}.{B}.x "
1717
"with Django {A}.{B}.y (found django-spanner {C}).".format(
18-
A=django.VERSION[0], B=django.VERSION[1], C=__version__,
18+
A=django.VERSION[0], B=django.VERSION[1], C=__version__
1919
)
2020
)

docs/conf.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,10 @@
350350
intersphinx_mapping = {
351351
"python": ("http://python.readthedocs.org/en/latest/", None),
352352
"google-auth": ("https://google-auth.readthedocs.io/en/stable", None),
353-
"google.api_core": ("https://googleapis.dev/python/google-api-core/latest/", None),
353+
"google.api_core": (
354+
"https://googleapis.dev/python/google-api-core/latest/",
355+
None,
356+
),
354357
"grpc": ("https://grpc.io/grpc/python/", None),
355358
}
356359

noxfile.py

+47-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,52 @@
1414
import shutil
1515

1616

17+
BLACK_VERSION = "black==19.10b0"
18+
BLACK_PATHS = [
19+
"django_spanner",
20+
"docs",
21+
"spanner_dbapi",
22+
"tests",
23+
"noxfile.py",
24+
"setup.py",
25+
]
26+
27+
28+
@nox.session(python="3.8")
29+
def lint(session):
30+
"""Run linters.
31+
32+
Returns a failure if the linters find linting errors or sufficiently
33+
serious code quality issues.
34+
"""
35+
session.install("flake8", BLACK_VERSION)
36+
session.run("black", "--check", *BLACK_PATHS)
37+
session.run("flake8", "django_spanner", "spanner_dbapi", "tests")
38+
39+
40+
@nox.session(python="3.8")
41+
def blacken(session):
42+
"""Run black.
43+
44+
Format code to uniform standard.
45+
46+
This currently uses Python 3.6 due to the automated Kokoro run of synthtool.
47+
That run uses an image that doesn't have 3.6 installed. Before updating this
48+
check the state of the `gcp_ubuntu_config` we use for that Kokoro run.
49+
"""
50+
session.install(BLACK_VERSION)
51+
session.run("black", *BLACK_PATHS)
52+
53+
54+
@nox.session(python="3.8")
55+
def lint_setup_py(session):
56+
"""Verify that setup.py is valid (including RST check)."""
57+
session.install("docutils", "pygments")
58+
session.run(
59+
"python", "setup.py", "check", "--restructuredtext", "--strict"
60+
)
61+
62+
1763
def default(session):
1864
# Install all test dependencies, then install this package in-place.
1965
session.install("mock", "pytest", "pytest-cov")
@@ -24,7 +70,7 @@ def default(session):
2470
"py.test",
2571
"--quiet",
2672
os.path.join("tests", "spanner_dbapi"),
27-
*session.posargs,
73+
*session.posargs
2874
)
2975

3076

setup.cfg

+9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ ignore =
55
W503 # allow line breaks before binary ops
66
W504 # allow line breaks after binary ops
77
E203 # allow whitespace before ':' (https://github.com/psf/black#slices)
8+
exclude =
9+
# Exclude generated code.
10+
**/_build/**
11+
12+
# Standard linting exemptions.
13+
__pycache__,
14+
.git,
15+
*.pyc,
16+
conf.py
817

918
[isort]
1019
use_parentheses = True

setup.py

+27-30
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@
1919
# 'Development Status :: 4 - Beta'
2020
# 'Development Status :: 5 - Production/Stable'
2121
release_status = "Development Status :: 3 - Alpha"
22-
dependencies = [
23-
'sqlparse >= 0.3.0',
24-
'google-cloud-spanner >= 1.8.0',
25-
]
22+
dependencies = ["sqlparse >= 0.3.0", "google-cloud-spanner >= 1.8.0"]
2623
extras = {}
2724

2825

@@ -36,30 +33,30 @@
3633

3734

3835
setup(
39-
name=name,
40-
version=version,
41-
description=description,
42-
long_description=readme,
43-
author='Google LLC',
44-
author_email='[email protected]',
45-
license='BSD',
46-
packages=find_packages(exclude=['tests']),
47-
install_requires=dependencies,
48-
url="https://github.com/googleapis/python-spanner-django",
49-
classifiers=[
50-
release_status,
51-
'Environment :: Web Environment',
52-
'Intended Audience :: Developers',
53-
'License :: OSI Approved :: BSD',
54-
'Operating System :: OS Independent',
55-
'Programming Language :: Python :: 3',
56-
'Programming Language :: Python :: 3.5',
57-
'Programming Language :: Python :: 3.6',
58-
'Programming Language :: Python :: 3.7',
59-
'Topic :: Utilities',
60-
'Framework :: Django',
61-
'Framework :: Django :: 2.2',
62-
],
63-
extras_require=extras,
64-
python_requires=">=3.5",
36+
name=name,
37+
version=version,
38+
description=description,
39+
long_description=readme,
40+
author="Google LLC",
41+
author_email="[email protected]",
42+
license="BSD",
43+
packages=find_packages(exclude=["tests"]),
44+
install_requires=dependencies,
45+
url="https://github.com/googleapis/python-spanner-django",
46+
classifiers=[
47+
release_status,
48+
"Environment :: Web Environment",
49+
"Intended Audience :: Developers",
50+
"License :: OSI Approved :: BSD",
51+
"Operating System :: OS Independent",
52+
"Programming Language :: Python :: 3",
53+
"Programming Language :: Python :: 3.5",
54+
"Programming Language :: Python :: 3.6",
55+
"Programming Language :: Python :: 3.7",
56+
"Topic :: Utilities",
57+
"Framework :: Django",
58+
"Framework :: Django :: 2.2",
59+
],
60+
extras_require=extras,
61+
python_requires=">=3.5",
6562
)

spanner_dbapi/connection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def get_table_column_schema(self, table_name):
108108
column_details = {}
109109
for column_name, is_nullable, spanner_type in rows:
110110
column_details[column_name] = ColumnDetails(
111-
null_ok=is_nullable == "YES", spanner_type=spanner_type,
111+
null_ok=is_nullable == "YES", spanner_type=spanner_type
112112
)
113113
return column_details
114114

spanner_dbapi/cursor.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,7 @@ def execute(self, sql, args=None):
104104
raise OperationalError(e.details if hasattr(e, "details") else e)
105105

106106
def __handle_update(self, sql, params):
107-
self._connection.in_transaction(
108-
self.__do_execute_update, sql, params,
109-
)
107+
self._connection.in_transaction(self.__do_execute_update, sql, params)
110108

111109
def __do_execute_update(self, transaction, sql, params, param_types=None):
112110
sql = ensure_where_clause(sql)
@@ -141,14 +139,14 @@ def __handle_insert(self, sql, params):
141139
# The common case of multiple values being passed in
142140
# non-complex pyformat args and need to be uploaded in one RPC.
143141
return self._connection.in_transaction(
144-
self.__do_execute_insert_homogenous, parts,
142+
self.__do_execute_insert_homogenous, parts
145143
)
146144
else:
147145
# All the other cases that are esoteric and need
148146
# transaction.execute_sql
149147
sql_params_list = parts.get("sql_params_list")
150148
return self._connection.in_transaction(
151-
self.__do_execute_insert_heterogenous, sql_params_list,
149+
self.__do_execute_insert_heterogenous, sql_params_list
152150
)
153151

154152
def __do_execute_insert_heterogenous(self, transaction, sql_params_list):

spanner_dbapi/parse_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ def rows_for_insert_or_update(columns, params, pyformat_args=None):
299299
# Now chop up the strides.
300300
strides = []
301301
for step in range(0, len(params), n_stride):
302-
stride = tuple(params[step: step + n_stride:])
302+
stride = tuple(params[step : step + n_stride :])
303303
strides.append(stride)
304304

305305
return strides

tests/spanner_dbapi/test_connect.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,26 @@ def test_connect(self):
3636
) as client_info_mock:
3737

3838
connection = connect(
39-
"test-instance", "test-database", PROJECT, CREDENTIALS, USER_AGENT
39+
"test-instance",
40+
"test-database",
41+
PROJECT,
42+
CREDENTIALS,
43+
USER_AGENT,
4044
)
4145

4246
self.assertIsInstance(connection, Connection)
4347
client_info_mock.assert_called_once_with(USER_AGENT)
4448

4549
client_mock.assert_called_once_with(
46-
project=PROJECT, credentials=CREDENTIALS, client_info=CLIENT_INFO
50+
project=PROJECT,
51+
credentials=CREDENTIALS,
52+
client_info=CLIENT_INFO,
4753
)
4854

4955
def test_instance_not_found(self):
5056
with mock.patch(
51-
"google.cloud.spanner_v1.instance.Instance.exists", return_value=False
57+
"google.cloud.spanner_v1.instance.Instance.exists",
58+
return_value=False,
5259
) as exists_mock:
5360

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

5966
def test_database_not_found(self):
6067
with mock.patch(
61-
"google.cloud.spanner_v1.instance.Instance.exists", return_value=True
68+
"google.cloud.spanner_v1.instance.Instance.exists",
69+
return_value=True,
6270
):
6371
with mock.patch(
64-
"google.cloud.spanner_v1.database.Database.exists", return_value=False
72+
"google.cloud.spanner_v1.database.Database.exists",
73+
return_value=False,
6574
) as exists_mock:
6675

6776
with self.assertRaises(ValueError):
@@ -88,7 +97,8 @@ def test_connect_database_id(self):
8897
"google.cloud.spanner_v1.instance.Instance.database"
8998
) as database_mock:
9099
with mock.patch(
91-
"google.cloud.spanner_v1.instance.Instance.exists", return_value=True
100+
"google.cloud.spanner_v1.instance.Instance.exists",
101+
return_value=True,
92102
):
93103
connection = connect("test-instance", DATABASE)
94104

0 commit comments

Comments
 (0)