diff --git a/.flake8 b/.flake8 index 29227d4c..2e438749 100644 --- a/.flake8 +++ b/.flake8 @@ -16,7 +16,7 @@ # Generated by synthtool. DO NOT EDIT! [flake8] -ignore = E203, E266, E501, W503 +ignore = E203, E231, E266, E501, W503 exclude = # Exclude generated code. **/proto/** diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 7e08e05a..757c9dca 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:5d8da01438ece4021d135433f2cf3227aa39ef0eaccc941d62aa35e6902832ae + digest: sha256:81ed5ecdfc7cac5b699ba4537376f3563f6f04122c4ec9e735d3b3dc1d43dd32 +# created: 2022-05-05T22:08:23.383410683Z diff --git a/.github/auto-approve.yml b/.github/auto-approve.yml new file mode 100644 index 00000000..311ebbb8 --- /dev/null +++ b/.github/auto-approve.yml @@ -0,0 +1,3 @@ +# https://github.com/googleapis/repo-automation-bots/tree/main/packages/auto-approve +processes: + - "OwlBotTemplateChanges" diff --git a/.github/auto-label.yaml b/.github/auto-label.yaml new file mode 100644 index 00000000..41bff0b5 --- /dev/null +++ b/.github/auto-label.yaml @@ -0,0 +1,15 @@ +# Copyright 2022 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. +requestsize: + enabled: true diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile index 4e1b1fb8..238b87b9 100644 --- a/.kokoro/docker/docs/Dockerfile +++ b/.kokoro/docker/docs/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ubuntu:20.04 +from ubuntu:22.04 ENV DEBIAN_FRONTEND noninteractive @@ -60,8 +60,24 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* \ && rm -f /var/cache/apt/archives/*.deb +###################### Install python 3.8.11 + +# Download python 3.8.11 +RUN wget https://www.python.org/ftp/python/3.8.11/Python-3.8.11.tgz + +# Extract files +RUN tar -xvf Python-3.8.11.tgz + +# Install python 3.8.11 +RUN ./Python-3.8.11/configure --enable-optimizations +RUN make altinstall + +###################### Install pip RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ - && python3.8 /tmp/get-pip.py \ + && python3 /tmp/get-pip.py \ && rm /tmp/get-pip.py +# Test pip +RUN python3 -m pip + CMD ["python3.8"] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 62eb5a77..46d23716 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: end-of-file-fixer - id: check-yaml - repo: https://github.com/psf/black - rev: 19.10b0 + rev: 22.3.0 hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 diff --git a/CHANGELOG.md b/CHANGELOG.md index 62ce484f..7ea96b9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,14 +14,21 @@ Older versions of this project were distributed as [pybigquery][0]. [2]: https://pypi.org/project/pybigquery/#history -### [1.4.3](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.4.2...v1.4.3) (2022-03-22) +## [1.4.4](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.4.3...v1.4.4) (2022-06-03) + + +### Documentation + +* fix changelog header to consistent size ([#461](https://github.com/googleapis/python-bigquery-sqlalchemy/issues/461)) ([177e70a](https://github.com/googleapis/python-bigquery-sqlalchemy/commit/177e70afb79420541021895fd0a082beb1704cf4)) + +## [1.4.3](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.4.2...v1.4.3) (2022-03-22) ### Bug Fixes * correct license text from Apache to MIT ([#436](https://github.com/googleapis/python-bigquery-sqlalchemy/issues/436)) ([dbf7501](https://github.com/googleapis/python-bigquery-sqlalchemy/commit/dbf7501c26157d3776f5a68254898758ee43a667)) -### [1.4.2](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.4.1...v1.4.2) (2022-03-22) +## [1.4.2](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.4.1...v1.4.2) (2022-03-22) ### Bug Fixes @@ -34,7 +41,7 @@ Older versions of this project were distributed as [pybigquery][0]. * require google-cloud-bigquery-storage to avoid performance warning ([#414](https://github.com/googleapis/python-bigquery-sqlalchemy/issues/414)) ([ff3273f](https://github.com/googleapis/python-bigquery-sqlalchemy/commit/ff3273feacfa1f34bb9090f28f11c2ac470759fc)) -### [1.4.1](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.4.0...v1.4.1) (2022-03-07) +## [1.4.1](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.4.0...v1.4.1) (2022-03-07) ### Bug Fixes @@ -60,14 +67,14 @@ Older versions of this project were distributed as [pybigquery][0]. * Enable support for 3.10 ([#381](https://www.github.com/googleapis/python-bigquery-sqlalchemy/issues/381)) ([4b3505b](https://www.github.com/googleapis/python-bigquery-sqlalchemy/commit/4b3505b3d3a4293ea127fc3c483e3e7de04fbd04)) -### [1.2.2](https://www.github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.2.1...v1.2.2) (2021-10-29) +## [1.2.2](https://www.github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.2.1...v1.2.2) (2021-10-29) ### Bug Fixes * avoid aliasing known tables used in CTEs ([#369](https://www.github.com/googleapis/python-bigquery-sqlalchemy/issues/369)) ([4b05d21](https://www.github.com/googleapis/python-bigquery-sqlalchemy/commit/4b05d21b8dc89339a69df87183f8893bf02459c5)) -### [1.2.1](https://www.github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.2.0...v1.2.1) (2021-10-27) +## [1.2.1](https://www.github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.2.0...v1.2.1) (2021-10-27) ### Bug Fixes diff --git a/dev_requirements.txt b/dev_requirements.txt index 933bd8fd..8ba88cdd 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,7 +1,6 @@ sqlalchemy>=1.1.9 google-cloud-bigquery>=1.6.0 future==0.18.2 - -pytest==6.2.5 -pytest-flake8==1.1.0 -pytz==2021.3 \ No newline at end of file +pytest===6.2.5 +pytest-flake8===1.1.0 # versions 1.1.1 and above require pytest 7 +pytz==2022.1 diff --git a/docs/conf.py b/docs/conf.py index 620d2a06..dbc0454b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -314,7 +314,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (root_doc, "sqlalchemy-bigquery", "sqlalchemy-bigquery Documentation", [author], 1,) + ( + root_doc, + "sqlalchemy-bigquery", + "sqlalchemy-bigquery Documentation", + [author], + 1, + ) ] # If true, show URL addresses after external links. @@ -355,7 +361,10 @@ intersphinx_mapping = { "python": ("https://python.readthedocs.org/en/latest/", None), "google-auth": ("https://googleapis.dev/python/google-auth/latest/", 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.github.io/grpc/python/", None), "proto-plus": ("https://proto-plus-python.readthedocs.io/en/latest/", None), "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), diff --git a/noxfile.py b/noxfile.py index b50a212c..8a2b685e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -21,18 +21,65 @@ import pathlib import re import shutil +import warnings import nox - -BLACK_VERSION = "black==19.10b0" -BLACK_PATHS = ["docs", "sqlalchemy_bigquery", "tests", "noxfile.py", "setup.py"] +BLACK_VERSION = "black==22.3.0" +ISORT_VERSION = "isort==5.10.1" +LINT_PATHS = ["docs", "sqlalchemy_bigquery", "tests", "noxfile.py", "setup.py"] DEFAULT_PYTHON_VERSION = "3.8" +UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] +UNIT_TEST_STANDARD_DEPENDENCIES = [ + "mock", + "asyncmock", + "pytest", + "pytest-cov", + "pytest-asyncio", +] +UNIT_TEST_EXTERNAL_DEPENDENCIES = [] +UNIT_TEST_LOCAL_DEPENDENCIES = [] +UNIT_TEST_DEPENDENCIES = [] +UNIT_TEST_EXTRAS = [ + "tests", +] +UNIT_TEST_EXTRAS_BY_PYTHON = { + "3.8": [ + "tests", + "alembic", + ], + "3.10": [ + "tests", + "geography", + ], +} + + # We're using two Python versions to test with sqlalchemy 1.3 and 1.4. SYSTEM_TEST_PYTHON_VERSIONS = ["3.8", "3.10"] -UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] +SYSTEM_TEST_STANDARD_DEPENDENCIES = [ + "mock", + "pytest", + "google-cloud-testutils", +] +SYSTEM_TEST_EXTERNAL_DEPENDENCIES = [] +SYSTEM_TEST_LOCAL_DEPENDENCIES = [] +SYSTEM_TEST_DEPENDENCIES = [] +SYSTEM_TEST_EXTRAS = [ + "tests", +] +SYSTEM_TEST_EXTRAS_BY_PYTHON = { + "3.8": [ + "tests", + "alembic", + ], + "3.10": [ + "tests", + "geography", + ], +} CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() @@ -61,7 +108,9 @@ def lint(session): """ session.install("flake8", BLACK_VERSION) session.run( - "black", "--check", *BLACK_PATHS, + "black", + "--check", + *LINT_PATHS, ) session.run("flake8", "sqlalchemy_bigquery", "tests") @@ -71,7 +120,28 @@ def blacken(session): """Run black. Format code to uniform standard.""" session.install(BLACK_VERSION) session.run( - "black", *BLACK_PATHS, + "black", + *LINT_PATHS, + ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def format(session): + """ + Run isort to sort imports. Then run black + to format code to uniform standard. + """ + session.install(BLACK_VERSION, ISORT_VERSION) + # Use the --fss option to sort imports using strict alphabetical order. + # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run( + "isort", + "--fss", + *LINT_PATHS, + ) + session.run( + "black", + *LINT_PATHS, ) @@ -82,29 +152,41 @@ def lint_setup_py(session): session.run("python", "setup.py", "check", "--restructuredtext", "--strict") +def install_unittest_dependencies(session, *constraints): + standard_deps = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_DEPENDENCIES + session.install(*standard_deps, *constraints) + + if UNIT_TEST_EXTERNAL_DEPENDENCIES: + warnings.warn( + "'unit_test_external_dependencies' is deprecated. Instead, please " + "use 'unit_test_dependencies' or 'unit_test_local_dependencies'.", + DeprecationWarning, + ) + session.install(*UNIT_TEST_EXTERNAL_DEPENDENCIES, *constraints) + + if UNIT_TEST_LOCAL_DEPENDENCIES: + session.install(*UNIT_TEST_LOCAL_DEPENDENCIES, *constraints) + + if UNIT_TEST_EXTRAS_BY_PYTHON: + extras = UNIT_TEST_EXTRAS_BY_PYTHON.get(session.python, []) + elif UNIT_TEST_EXTRAS: + extras = UNIT_TEST_EXTRAS + else: + extras = [] + + if extras: + session.install("-e", f".[{','.join(extras)}]", *constraints) + else: + session.install("-e", ".", *constraints) + + def default(session): # Install all test dependencies, then install this package in-place. constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" ) - session.install( - "mock", - "asyncmock", - "pytest", - "pytest-cov", - "pytest-asyncio", - "-c", - constraints_path, - ) - - if session.python == "3.8": - extras = "[tests,alembic]" - elif session.python == "3.10": - extras = "[tests,geography]" - else: - extras = "[tests]" - session.install("-e", f".{extras}", "-c", constraints_path) + install_unittest_dependencies(session, "-c", constraints_path) # Run py.test against the unit tests. session.run( @@ -128,6 +210,35 @@ def unit(session): default(session) +def install_systemtest_dependencies(session, *constraints): + + # Use pre-release gRPC for system tests. + session.install("--pre", "grpcio") + + session.install(*SYSTEM_TEST_STANDARD_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_EXTERNAL_DEPENDENCIES: + session.install(*SYSTEM_TEST_EXTERNAL_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_LOCAL_DEPENDENCIES: + session.install("-e", *SYSTEM_TEST_LOCAL_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_DEPENDENCIES: + session.install("-e", *SYSTEM_TEST_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_EXTRAS_BY_PYTHON: + extras = SYSTEM_TEST_EXTRAS_BY_PYTHON.get(session.python, []) + elif SYSTEM_TEST_EXTRAS: + extras = SYSTEM_TEST_EXTRAS + else: + extras = [] + + if extras: + session.install("-e", f".[{','.join(extras)}]", *constraints) + else: + session.install("-e", ".", *constraints) + + @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) def system(session): """Run the system test suite.""" @@ -150,19 +261,7 @@ def system(session): if not system_test_exists and not system_test_folder_exists: session.skip("System tests were not found") - # Use pre-release gRPC for system tests. - session.install("--pre", "grpcio") - - # Install all test dependencies, then install this package into the - # virtualenv's dist-packages. - session.install("mock", "pytest", "google-cloud-testutils", "-c", constraints_path) - if session.python == "3.8": - extras = "[tests,alembic]" - elif session.python == "3.10": - extras = "[tests,geography]" - else: - extras = "[tests]" - session.install("-e", f".{extras}", "-c", constraints_path) + install_systemtest_dependencies(session, "-c", constraints_path) # Run py.test against the system tests. if system_test_exists: diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 85f5836d..a40410b5 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -29,7 +29,8 @@ # WARNING - WARNING - WARNING - WARNING - WARNING # WARNING - WARNING - WARNING - WARNING - WARNING -BLACK_VERSION = "black==19.10b0" +BLACK_VERSION = "black==22.3.0" +ISORT_VERSION = "isort==5.10.1" # Copy `noxfile_config.py` to your directory and modify it instead. @@ -168,12 +169,33 @@ def lint(session: nox.sessions.Session) -> None: @nox.session def blacken(session: nox.sessions.Session) -> None: + """Run black. Format code to uniform standard.""" session.install(BLACK_VERSION) python_files = [path for path in os.listdir(".") if path.endswith(".py")] session.run("black", *python_files) +# +# format = isort + black +# + + +@nox.session +def format(session: nox.sessions.Session) -> None: + """ + Run isort to sort imports. Then run black + to format code to uniform standard. + """ + session.install(BLACK_VERSION, ISORT_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + # Use the --fss option to sort imports using strict alphabetical order. + # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run("isort", "--fss", *python_files) + session.run("black", *python_files) + + # # Sample Tests # @@ -253,7 +275,7 @@ def py(session: nox.sessions.Session) -> None: def _get_repo_root() -> Optional[str]: - """ Returns the root folder of the project. """ + """Returns the root folder of the project.""" # Get root of this repository. Assume we don't have directories nested deeper than 10 items. p = Path(os.getcwd()) for i in range(10): diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt index 4055c210..afd11b44 100644 --- a/samples/snippets/requirements-test.txt +++ b/samples/snippets/requirements-test.txt @@ -1,6 +1,6 @@ attrs==21.4.0 -click==8.0.4 -google-auth==2.6.0 +click==8.1.2 +google-auth==2.6.2 google-cloud-testutils==1.3.1 iniconfig==1.1.1 packaging==21.3 @@ -9,7 +9,7 @@ py==1.11.0 pyasn1==0.4.8 pyasn1-modules==0.2.8 pyparsing==3.0.7 -pytest==6.2.5 +pytest===6.2.5 rsa==4.8 six==1.16.0 toml==0.10.2 diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index 4266837c..241c5e1e 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,34 +1,34 @@ -alembic==1.7.6 +alembic==1.7.7 certifi==2021.10.8 charset-normalizer==2.0.12 future==0.18.2 geoalchemy2==0.11.1 -google-api-core[grpc]==2.7.0 -google-auth==2.6.0 -google-cloud-bigquery==2.34.2 +google-api-core[grpc]==2.7.1 +google-auth==2.6.2 +google-cloud-bigquery==3.0.1 google-cloud-core==2.2.3 google-crc32c==1.3.0 google-resumable-media==2.3.2 -googleapis-common-protos==1.55.0 +googleapis-common-protos==1.56.0 greenlet==1.1.2 -grpcio==1.44.0 -grpcio-status==1.44.0 +grpcio==1.45.0 +grpcio-status==1.45.0 idna==3.3 -importlib-resources==5.4.0 -mako==1.1.6 -markupsafe==2.1.0 +importlib-resources==5.6.0 +mako==1.2.0 +markupsafe==2.1.1 packaging==21.3 proto-plus==1.20.3 -protobuf==3.19.4 +protobuf==3.20.0 pyasn1==0.4.8 pyasn1-modules==0.2.8 pyparsing==3.0.7 python-dateutil==2.8.2 -pytz==2021.3 +pytz==2022.1 requests==2.27.1 rsa==4.8 shapely==1.8.1.post1 six==1.16.0 -sqlalchemy==1.4.27 +sqlalchemy===1.4.27 typing-extensions==4.1.1 -urllib3==1.26.8 +urllib3==1.26.9 diff --git a/scripts/readme-gen/readme_gen.py b/scripts/readme-gen/readme_gen.py index d309d6e9..91b59676 100644 --- a/scripts/readme-gen/readme_gen.py +++ b/scripts/readme-gen/readme_gen.py @@ -28,7 +28,10 @@ jinja_env = jinja2.Environment( trim_blocks=True, loader=jinja2.FileSystemLoader( - os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates')))) + os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")) + ), + autoescape=True, +) README_TMPL = jinja_env.get_template('README.tmpl.rst') diff --git a/sqlalchemy_bigquery/_struct.py b/sqlalchemy_bigquery/_struct.py index a3d9aba4..6ebb5a64 100644 --- a/sqlalchemy_bigquery/_struct.py +++ b/sqlalchemy_bigquery/_struct.py @@ -124,12 +124,14 @@ def _field_index(self, name, operator): bindparam_type=sqlalchemy.types.String(), ) - else: def _field_index(self, name, operator): return sqlalchemy.sql.default_comparator._check_literal( - self.expr, operator, name, bindparam_type=sqlalchemy.types.String(), + self.expr, + operator, + name, + bindparam_type=sqlalchemy.types.String(), ) diff --git a/sqlalchemy_bigquery/base.py b/sqlalchemy_bigquery/base.py index ca1772a0..48455836 100644 --- a/sqlalchemy_bigquery/base.py +++ b/sqlalchemy_bigquery/base.py @@ -76,7 +76,8 @@ class BigQueryIdentifierPreparer(IdentifierPreparer): def __init__(self, dialect): super(BigQueryIdentifierPreparer, self).__init__( - dialect, initial_quote="`", + dialect, + initial_quote="`", ) def quote_column(self, value): @@ -349,7 +350,7 @@ def group_by_clause(self, select, **kw): __expanding_conflict = "" if __sqlalchemy_version_info < (1, 4, 27) else "__" __in_expanding_bind = _helpers.substitute_string_re_method( - fr""" + rf""" \sIN\s\( # ' IN (' ( {__expanding_conflict}\[ # Expanding placeholder @@ -435,7 +436,7 @@ def visit_notendswith_op_binary(self, binary, operator, **kw): __placeholder = re.compile(r"%\(([^\]:]+)(:[^\]:]+)?\)s$").match __expanded_param = re.compile( - fr"\({__expanding_conflict}\[" fr"{__expanding_text}" fr"_[^\]]+\]\)$" + rf"\({__expanding_conflict}\[" rf"{__expanding_text}" rf"_[^\]]+\]\)$" ).match __remove_type_parameter = _helpers.substitute_string_re_method( @@ -681,8 +682,7 @@ def literal_processor(self, dialect): class BQClassTaggedStr(sqlalchemy.sql.type_api.TypeEngine): - """Type that can get literals via str - """ + """Type that can get literals via str""" @staticmethod def process_literal_as_class_tagged_str(value): @@ -693,8 +693,7 @@ def literal_processor(self, dialect): class BQTimestamp(sqlalchemy.sql.type_api.TypeEngine): - """Type that can get literals via str - """ + """Type that can get literals via str""" @staticmethod def process_timestamp_literal(value): diff --git a/sqlalchemy_bigquery/geography.py b/sqlalchemy_bigquery/geography.py index 16384dd4..ec96a715 100644 --- a/sqlalchemy_bigquery/geography.py +++ b/sqlalchemy_bigquery/geography.py @@ -100,7 +100,9 @@ class Lake(Base): def __init__(self): super().__init__( - geometry_type=None, spatial_index=False, srid=SRID, + geometry_type=None, + spatial_index=False, + srid=SRID, ) self.extended = True @@ -198,32 +200,74 @@ def _fixup_st_arguments(element, compiler, **kw): st_boundary=(GEOGRAPHY,), st_centroid=(GEOGRAPHY,), st_centroid_agg=(GEOGRAPHY,), - st_closestpoint=(GEOGRAPHY, GEOGRAPHY,), + st_closestpoint=( + GEOGRAPHY, + GEOGRAPHY, + ), st_clusterdbscan=(GEOGRAPHY,), - st_contains=(GEOGRAPHY, GEOGRAPHY,), + st_contains=( + GEOGRAPHY, + GEOGRAPHY, + ), st_convexhull=(GEOGRAPHY,), - st_coveredby=(GEOGRAPHY, GEOGRAPHY,), - st_covers=(GEOGRAPHY, GEOGRAPHY,), - st_difference=(GEOGRAPHY, GEOGRAPHY,), + st_coveredby=( + GEOGRAPHY, + GEOGRAPHY, + ), + st_covers=( + GEOGRAPHY, + GEOGRAPHY, + ), + st_difference=( + GEOGRAPHY, + GEOGRAPHY, + ), st_dimension=(GEOGRAPHY,), - st_disjoint=(GEOGRAPHY, GEOGRAPHY,), - st_distance=(GEOGRAPHY, GEOGRAPHY,), + st_disjoint=( + GEOGRAPHY, + GEOGRAPHY, + ), + st_distance=( + GEOGRAPHY, + GEOGRAPHY, + ), st_dump=(GEOGRAPHY,), - st_dwithin=(GEOGRAPHY, GEOGRAPHY,), + st_dwithin=( + GEOGRAPHY, + GEOGRAPHY, + ), st_endpoint=(GEOGRAPHY,), - st_equals=(GEOGRAPHY, GEOGRAPHY,), + st_equals=( + GEOGRAPHY, + GEOGRAPHY, + ), st_exteriorring=(GEOGRAPHY,), st_geohash=(GEOGRAPHY,), - st_intersection=(GEOGRAPHY, GEOGRAPHY,), - st_intersects=(GEOGRAPHY, GEOGRAPHY,), + st_intersection=( + GEOGRAPHY, + GEOGRAPHY, + ), + st_intersects=( + GEOGRAPHY, + GEOGRAPHY, + ), st_intersectsbox=(GEOGRAPHY,), st_iscollection=(GEOGRAPHY,), st_isempty=(GEOGRAPHY,), st_length=(GEOGRAPHY,), - st_makeline=(GEOGRAPHY, GEOGRAPHY,), - st_makepolygon=(GEOGRAPHY, GEOGRAPHY,), + st_makeline=( + GEOGRAPHY, + GEOGRAPHY, + ), + st_makepolygon=( + GEOGRAPHY, + GEOGRAPHY, + ), st_makepolygonoriented=(GEOGRAPHY,), - st_maxdistance=(GEOGRAPHY, GEOGRAPHY,), + st_maxdistance=( + GEOGRAPHY, + GEOGRAPHY, + ), st_npoints=(GEOGRAPHY,), st_numpoints=(GEOGRAPHY,), st_perimeter=(GEOGRAPHY,), @@ -231,10 +275,19 @@ def _fixup_st_arguments(element, compiler, **kw): st_simplify=(GEOGRAPHY,), st_snaptogrid=(GEOGRAPHY,), st_startpoint=(GEOGRAPHY,), - st_touches=(GEOGRAPHY, GEOGRAPHY,), - st_union=(GEOGRAPHY, GEOGRAPHY,), + st_touches=( + GEOGRAPHY, + GEOGRAPHY, + ), + st_union=( + GEOGRAPHY, + GEOGRAPHY, + ), st_union_agg=(GEOGRAPHY,), - st_within=(GEOGRAPHY, GEOGRAPHY,), + st_within=( + GEOGRAPHY, + GEOGRAPHY, + ), st_x=(GEOGRAPHY,), st_y=(GEOGRAPHY,), ) diff --git a/sqlalchemy_bigquery/version.py b/sqlalchemy_bigquery/version.py index 70dfa1a1..dab676d1 100644 --- a/sqlalchemy_bigquery/version.py +++ b/sqlalchemy_bigquery/version.py @@ -17,4 +17,4 @@ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__version__ = "1.4.3" +__version__ = "1.4.4" diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index e69de29b..9d2df4fe 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -0,0 +1,12 @@ +# This constraints file is used to check that lower bounds +# are correct in setup.py +# List *all* library dependencies and extras in this file. +# Pin the version to the lower bound. +# +# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", +sqlalchemy==1.2.0 +google-auth==1.25.0 +google-cloud-bigquery==2.25.2 +google-cloud-bigquery-storage==2.0.0 +google-api-core==1.31.5 +pyarrow==3.0.0 diff --git a/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py b/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py index 156e6167..5d575fc7 100644 --- a/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py +++ b/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py @@ -69,7 +69,6 @@ def literal(value): with mock.patch("sqlalchemy.testing.suite.test_types.literal", literal): super(TimestampMicrosecondsTest, self).test_literal() - else: from sqlalchemy.testing.suite import ( FetchLimitOffsetTest as _FetchLimitOffsetTest, @@ -95,7 +94,9 @@ def test_limit_render_multiple_times(self, connection): u = sqlalchemy.union(select(stmt), select(stmt)).subquery().select() self._assert_result( - connection, u, [(1,)], + connection, + u, + [(1,)], ) del DifficultParametersTest # exercises column names illegal in BQ @@ -193,7 +194,10 @@ def test_select_exists(self, connection): eq_( connection.execute( select([stuff.c.id]).where( - and_(stuff.c.id == 1, exists().where(stuff.c.data == "some data"),) + and_( + stuff.c.id == 1, + exists().where(stuff.c.data == "some data"), + ) ) ).fetchall(), [(1,)], diff --git a/tests/system/conftest.py b/tests/system/conftest.py index 04803ebd..23d244f2 100644 --- a/tests/system/conftest.py +++ b/tests/system/conftest.py @@ -53,7 +53,9 @@ def load_sample_data( with open(DATA_DIR / filename, "rb") as data_file: return bigquery_client.load_table_from_file( - data_file, full_table_id, job_config=sample_config, + data_file, + full_table_id, + job_config=sample_config, ) @@ -86,7 +88,9 @@ def bigquery_dataset( filename="sample_one_row.json", ) job2.result() - view = bigquery.Table(f"{project_id}.{dataset_id}.sample_view",) + view = bigquery.Table( + f"{project_id}.{dataset_id}.sample_view", + ) view.view_query = f"SELECT string FROM `{dataset_id}.sample`" bigquery_client.create_table(view) yield dataset_id diff --git a/tests/system/test__struct.py b/tests/system/test__struct.py index 24863056..bb7958c9 100644 --- a/tests/system/test__struct.py +++ b/tests/system/test__struct.py @@ -148,7 +148,10 @@ def test_unnest_and_struct_access_233(engine, bigquery_dataset, metadata): metadata.create_all(engine) conn.execute( - mock_table.insert(), dict(mock_id="x"), dict(mock_id="y"), dict(mock_id="z"), + mock_table.insert(), + dict(mock_id="x"), + dict(mock_id="y"), + dict(mock_id="z"), ) conn.execute( another_mock_table.insert(), @@ -160,7 +163,8 @@ def test_unnest_and_struct_access_233(engine, bigquery_dataset, metadata): ).subquery() join = mock_table.join( - subquery, subquery.c.another_mock_objects["object_id"] == mock_table.c.mock_id, + subquery, + subquery.c.another_mock_objects["object_id"] == mock_table.c.mock_id, ) query = select(mock_table).select_from(join) diff --git a/tests/system/test_geography.py b/tests/system/test_geography.py index 18bcc7d4..7189eebb 100644 --- a/tests/system/test_geography.py +++ b/tests/system/test_geography.py @@ -56,7 +56,8 @@ def test_geoalchemy2_core(bigquery_dataset): conn.execute( lake_table.insert().values( - name="Majeur", geog="POLYGON((0 0,1 0,1 1,0 1,0 0))", + name="Majeur", + geog="POLYGON((0 0,1 0,1 1,0 1,0 0))", ) ) @@ -113,7 +114,8 @@ def test_geoalchemy2_core(bigquery_dataset): conn.execute( lake_table.insert().values( - name="test2", geog=WKT("POLYGON((1 0,3 0,3 2,1 2,1 0))"), + name="test2", + geog=WKT("POLYGON((1 0,3 0,3 2,1 2,1 0))"), ) ) assert ( diff --git a/tests/system/test_helpers.py b/tests/system/test_helpers.py index 62f22688..42cfab7f 100644 --- a/tests/system/test_helpers.py +++ b/tests/system/test_helpers.py @@ -54,7 +54,8 @@ def test_create_bigquery_client_with_credentials_path_respects_project( https://github.com/googleapis/python-bigquery-sqlalchemy/issues/48 """ bqclient = module_under_test.create_bigquery_client( - credentials_path=credentials_path, project_id="connection-url-project", + credentials_path=credentials_path, + project_id="connection-url-project", ) assert bqclient.project == "connection-url-project" @@ -76,7 +77,8 @@ def test_create_bigquery_client_with_credentials_info_respects_project( https://github.com/googleapis/python-bigquery-sqlalchemy/issues/48 """ bqclient = module_under_test.create_bigquery_client( - credentials_info=credentials_info, project_id="connection-url-project", + credentials_info=credentials_info, + project_id="connection-url-project", ) assert bqclient.project == "connection-url-project" @@ -98,6 +100,7 @@ def test_create_bigquery_client_with_credentials_base64_respects_project( https://github.com/googleapis/python-bigquery-sqlalchemy/issues/48 """ bqclient = module_under_test.create_bigquery_client( - credentials_base64=credentials_base64, project_id="connection-url-project", + credentials_base64=credentials_base64, + project_id="connection-url-project", ) assert bqclient.project == "connection-url-project" diff --git a/tests/system/test_sqlalchemy_bigquery.py b/tests/system/test_sqlalchemy_bigquery.py index 564c5e68..0772e10a 100644 --- a/tests/system/test_sqlalchemy_bigquery.py +++ b/tests/system/test_sqlalchemy_bigquery.py @@ -305,7 +305,8 @@ def test_content_from_reflect(engine, table_one_row): def test_unicode(engine, table_one_row): unicode_str = "白人看不懂" returned_str = sqlalchemy.select( - [expression.bindparam("好", unicode_str)], from_obj=table_one_row, + [expression.bindparam("好", unicode_str)], + from_obj=table_one_row, ).scalar() assert returned_str == unicode_str @@ -756,7 +757,9 @@ def test_unnest(engine, bigquery_dataset): conn = engine.connect() metadata = MetaData() table = Table( - f"{bigquery_dataset}.test_unnest", metadata, Column("objects", ARRAY(String)), + f"{bigquery_dataset}.test_unnest", + metadata, + Column("objects", ARRAY(String)), ) metadata.create_all(engine) conn.execute( diff --git a/tests/unit/fauxdbi.py b/tests/unit/fauxdbi.py index 631996af..c6ee2a73 100644 --- a/tests/unit/fauxdbi.py +++ b/tests/unit/fauxdbi.py @@ -172,7 +172,8 @@ def __normalize_array_types(self, m): return m.group(0).replace("<", "_").replace(">", "_") def __handle_array_types( - self, operation, + self, + operation, ): if self.__create_table(operation): return self.__normalize_array_types(operation) @@ -187,7 +188,8 @@ def __parse_dateish(type_, value): if type_ == "datetime": return datetime.datetime.strptime( - value, "%Y-%m-%d %H:%M:%S.%f" if "." in value else "%Y-%m-%d %H:%M:%S", + value, + "%Y-%m-%d %H:%M:%S.%f" if "." in value else "%Y-%m-%d %H:%M:%S", ) elif type_ == "date": return datetime.date(*map(int, value.split("-"))) diff --git a/tests/unit/test__struct.py b/tests/unit/test__struct.py index 26ccec54..77577066 100644 --- a/tests/unit/test__struct.py +++ b/tests/unit/test__struct.py @@ -52,7 +52,9 @@ def test_bind_processor(): def _col(): return sqlalchemy.Table( - "t", sqlalchemy.MetaData(), sqlalchemy.Column("person", _test_struct()), + "t", + sqlalchemy.MetaData(), + sqlalchemy.Column("person", _test_struct()), ).c.person diff --git a/tests/unit/test_catalog_functions.py b/tests/unit/test_catalog_functions.py index fd7d0d63..78614c9f 100644 --- a/tests/unit/test_catalog_functions.py +++ b/tests/unit/test_catalog_functions.py @@ -127,9 +127,15 @@ def test_get_indexes(faux_conn): client.tables.foo.clustering_fields = ["user_email", "store_code"] assert faux_conn.dialect.get_indexes(faux_conn, "foo") == [ - dict(name="partition", column_names=["tm"], unique=False,), dict( - name="clustering", column_names=["user_email", "store_code"], unique=False, + name="partition", + column_names=["tm"], + unique=False, + ), + dict( + name="clustering", + column_names=["user_email", "store_code"], + unique=False, ), ] diff --git a/tests/unit/test_comments.py b/tests/unit/test_comments.py index df7f07a3..6feba866 100644 --- a/tests/unit/test_comments.py +++ b/tests/unit/test_comments.py @@ -39,7 +39,9 @@ def test_inline_comments(faux_conn): def test_set_drop_table_comment(faux_conn): table = setup_table( - faux_conn, "some_table", sqlalchemy.Column("id", sqlalchemy.Integer), + faux_conn, + "some_table", + sqlalchemy.Column("id", sqlalchemy.Integer), ) dialect = faux_conn.dialect diff --git a/tests/unit/test_compiler.py b/tests/unit/test_compiler.py index 84a93508..db02e593 100644 --- a/tests/unit/test_compiler.py +++ b/tests/unit/test_compiler.py @@ -26,7 +26,9 @@ def test_constraints_are_ignored(faux_conn, metadata): sqlalchemy.Table( - "ref", metadata, sqlalchemy.Column("id", sqlalchemy.Integer), + "ref", + metadata, + sqlalchemy.Column("id", sqlalchemy.Integer), ) sqlalchemy.Table( "some_table", diff --git a/tests/unit/test_geography.py b/tests/unit/test_geography.py index fafc0a80..25d3c605 100644 --- a/tests/unit/test_geography.py +++ b/tests/unit/test_geography.py @@ -25,8 +25,7 @@ def test_geoalchemy2_core(faux_conn, last_query): - """Make sure GeoAlchemy 2 Core Tutorial works as adapted to only having geometry - """ + """Make sure GeoAlchemy 2 Core Tutorial works as adapted to only having geometry""" conn = faux_conn # Create the Table @@ -42,7 +41,8 @@ def test_geoalchemy2_core(faux_conn, last_query): conn.execute( lake_table.insert().values( - name="Majeur", geog="POLYGON((0 0,1 0,1 1,0 1,0 0))", + name="Majeur", + geog="POLYGON((0 0,1 0,1 1,0 1,0 0))", ) ) @@ -132,7 +132,8 @@ def test_geoalchemy2_core(faux_conn, last_query): conn.execute( lake_table.insert().values( - name="test2", geog=WKT("POLYGON((1 0,3 0,3 2,1 2,1 0))"), + name="test2", + geog=WKT("POLYGON((1 0,3 0,3 2,1 2,1 0))"), ) ) last_query( diff --git a/tests/unit/test_helpers.py b/tests/unit/test_helpers.py index 9400f1ed..02bc8bee 100644 --- a/tests/unit/test_helpers.py +++ b/tests/unit/test_helpers.py @@ -34,8 +34,8 @@ def module_under_test(): def test_create_bigquery_client_with_credentials_path(monkeypatch, module_under_test): mock_service_account = mock.create_autospec(service_account.Credentials) - mock_service_account.from_service_account_file.return_value = AnonymousCredentialsWithProject( - "service-account-project" + mock_service_account.from_service_account_file.return_value = ( + AnonymousCredentialsWithProject("service-account-project") ) monkeypatch.setattr(service_account, "Credentials", mock_service_account) @@ -54,13 +54,14 @@ def test_create_bigquery_client_with_credentials_path_respects_project( https://github.com/googleapis/python-bigquery-sqlalchemy/issues/48 """ mock_service_account = mock.create_autospec(service_account.Credentials) - mock_service_account.from_service_account_file.return_value = AnonymousCredentialsWithProject( - "service-account-project" + mock_service_account.from_service_account_file.return_value = ( + AnonymousCredentialsWithProject("service-account-project") ) monkeypatch.setattr(service_account, "Credentials", mock_service_account) bqclient = module_under_test.create_bigquery_client( - credentials_path="path/to/key.json", project_id="connection-url-project", + credentials_path="path/to/key.json", + project_id="connection-url-project", ) assert bqclient.project == "connection-url-project" @@ -68,8 +69,8 @@ def test_create_bigquery_client_with_credentials_path_respects_project( def test_create_bigquery_client_with_credentials_info(monkeypatch, module_under_test): mock_service_account = mock.create_autospec(service_account.Credentials) - mock_service_account.from_service_account_info.return_value = AnonymousCredentialsWithProject( - "service-account-project" + mock_service_account.from_service_account_info.return_value = ( + AnonymousCredentialsWithProject("service-account-project") ) monkeypatch.setattr(service_account, "Credentials", mock_service_account) @@ -91,8 +92,8 @@ def test_create_bigquery_client_with_credentials_info_respects_project( https://github.com/googleapis/python-bigquery-sqlalchemy/issues/48 """ mock_service_account = mock.create_autospec(service_account.Credentials) - mock_service_account.from_service_account_info.return_value = AnonymousCredentialsWithProject( - "service-account-project" + mock_service_account.from_service_account_info.return_value = ( + AnonymousCredentialsWithProject("service-account-project") ) monkeypatch.setattr(service_account, "Credentials", mock_service_account) @@ -109,8 +110,8 @@ def test_create_bigquery_client_with_credentials_info_respects_project( def test_create_bigquery_client_with_credentials_base64(monkeypatch, module_under_test): mock_service_account = mock.create_autospec(service_account.Credentials) - mock_service_account.from_service_account_info.return_value = AnonymousCredentialsWithProject( - "service-account-project" + mock_service_account.from_service_account_info.return_value = ( + AnonymousCredentialsWithProject("service-account-project") ) monkeypatch.setattr(service_account, "Credentials", mock_service_account) @@ -135,8 +136,8 @@ def test_create_bigquery_client_with_credentials_base64_respects_project( https://github.com/googleapis/python-bigquery-sqlalchemy/issues/48 """ mock_service_account = mock.create_autospec(service_account.Credentials) - mock_service_account.from_service_account_info.return_value = AnonymousCredentialsWithProject( - "service-account-project" + mock_service_account.from_service_account_info.return_value = ( + AnonymousCredentialsWithProject("service-account-project") ) monkeypatch.setattr(service_account, "Credentials", mock_service_account) @@ -147,7 +148,8 @@ def test_create_bigquery_client_with_credentials_base64_respects_project( credentials_base64 = base64.b64encode(json.dumps(credentials_info).encode()) bqclient = module_under_test.create_bigquery_client( - credentials_base64=credentials_base64, project_id="connection-url-project", + credentials_base64=credentials_base64, + project_id="connection-url-project", ) assert bqclient.project == "connection-url-project" diff --git a/tests/unit/test_select.py b/tests/unit/test_select.py index 33c657f7..08fc0225 100644 --- a/tests/unit/test_select.py +++ b/tests/unit/test_select.py @@ -174,7 +174,9 @@ def test_select_struct(faux_conn, metadata): from sqlalchemy_bigquery import STRUCT table = sqlalchemy.Table( - "t", metadata, sqlalchemy.Column("x", STRUCT(y=sqlalchemy.Integer)), + "t", + metadata, + sqlalchemy.Column("x", STRUCT(y=sqlalchemy.Integer)), ) faux_conn.ex("create table t (x RECORD)") @@ -198,7 +200,9 @@ def test_force_quote(faux_conn): from sqlalchemy.sql.elements import quoted_name table = setup_table( - faux_conn, "t", sqlalchemy.Column(quoted_name("foo", True), sqlalchemy.Integer), + faux_conn, + "t", + sqlalchemy.Column(quoted_name("foo", True), sqlalchemy.Integer), ) faux_conn.execute(sqlalchemy.select([table])) assert faux_conn.test_data["execute"][-1][0] == ("SELECT `t`.`foo` \nFROM `t`") @@ -435,7 +439,9 @@ def test_unnest_w_no_table_references(faux_conn, alias): def test_array_indexing(faux_conn, metadata): t = sqlalchemy.Table( - "t", metadata, sqlalchemy.Column("a", sqlalchemy.ARRAY(sqlalchemy.String)), + "t", + metadata, + sqlalchemy.Column("a", sqlalchemy.ARRAY(sqlalchemy.String)), ) got = str(sqlalchemy.select([t.c.a[0]]).compile(faux_conn.engine)) assert got == "SELECT `t`.`a`[OFFSET(%(a_1:INT64)s)] AS `anon_1` \nFROM `t`" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy