From 74e75e89ce3a5ac18112b2c1c33248445ff072e4 Mon Sep 17 00:00:00 2001 From: Lingqing Gan Date: Mon, 6 May 2024 16:46:27 -0700 Subject: [PATCH 1/6] feat: support insertAll for range (#1909) * feat: support insertAll for range * revert INTERVAL regex * lint * add unit test * lint --- google/cloud/bigquery/_helpers.py | 52 +++++++++++++- tests/unit/test__helpers.py | 114 +++++++++++++++++++++++++++++- 2 files changed, 162 insertions(+), 4 deletions(-) diff --git a/google/cloud/bigquery/_helpers.py b/google/cloud/bigquery/_helpers.py index 083eb9f9d..668b4ca3d 100644 --- a/google/cloud/bigquery/_helpers.py +++ b/google/cloud/bigquery/_helpers.py @@ -50,6 +50,7 @@ r"(?P-?\d+) " r"(?P-?)(?P\d+):(?P\d+):(?P\d+)\.?(?P\d*)?$" ) +_RANGE_PATTERN = re.compile(r"\[.*, .*\)") BIGQUERY_EMULATOR_HOST = "BIGQUERY_EMULATOR_HOST" """Environment variable defining host for emulator.""" @@ -334,9 +335,8 @@ def _range_from_json(value, field): The parsed range object from ``value`` if the ``field`` is not null (otherwise it is :data:`None`). """ - range_literal = re.compile(r"\[.*, .*\)") if _not_null(value, field): - if range_literal.match(value): + if _RANGE_PATTERN.match(value): start, end = value[1:-1].split(", ") start = _range_element_from_json(start, field.range_element_type) end = _range_element_from_json(end, field.range_element_type) @@ -531,6 +531,52 @@ def _time_to_json(value): return value +def _range_element_to_json(value, element_type=None): + """Coerce 'value' to an JSON-compatible representation.""" + if value is None: + return None + elif isinstance(value, str): + if value.upper() in ("UNBOUNDED", "NULL"): + return None + else: + # We do not enforce range element value to be valid to reduce + # redundancy with backend. + return value + elif ( + element_type and element_type.element_type.upper() in _SUPPORTED_RANGE_ELEMENTS + ): + converter = _SCALAR_VALUE_TO_JSON_ROW.get(element_type.element_type.upper()) + return converter(value) + else: + raise ValueError( + f"Unsupported RANGE element type {element_type}, or " + "element type is empty. Must be DATE, DATETIME, or " + "TIMESTAMP" + ) + + +def _range_field_to_json(range_element_type, value): + """Coerce 'value' to an JSON-compatible representation.""" + if isinstance(value, str): + # string literal + if _RANGE_PATTERN.match(value): + start, end = value[1:-1].split(", ") + else: + raise ValueError(f"RANGE literal {value} has incorrect format") + elif isinstance(value, dict): + # dictionary + start = value.get("start") + end = value.get("end") + else: + raise ValueError( + f"Unsupported type of RANGE value {value}, must be " "string or dict" + ) + + start = _range_element_to_json(start, range_element_type) + end = _range_element_to_json(end, range_element_type) + return {"start": start, "end": end} + + # Converters used for scalar values marshalled to the BigQuery API, such as in # query parameters or the tabledata.insert API. _SCALAR_VALUE_TO_JSON_ROW = { @@ -676,6 +722,8 @@ def _single_field_to_json(field, row_value): if field.field_type == "RECORD": return _record_field_to_json(field.fields, row_value) + if field.field_type == "RANGE": + return _range_field_to_json(field.range_element_type, row_value) return _scalar_field_to_json(field, row_value) diff --git a/tests/unit/test__helpers.py b/tests/unit/test__helpers.py index a50625e2a..1bf21479f 100644 --- a/tests/unit/test__helpers.py +++ b/tests/unit/test__helpers.py @@ -1049,10 +1049,22 @@ def test_w_datetime(self): self.assertEqual(self._call_fut(when), "12:13:41") -def _make_field(field_type, mode="NULLABLE", name="testing", fields=()): +def _make_field( + field_type, + mode="NULLABLE", + name="testing", + fields=(), + range_element_type=None, +): from google.cloud.bigquery.schema import SchemaField - return SchemaField(name=name, field_type=field_type, mode=mode, fields=fields) + return SchemaField( + name=name, + field_type=field_type, + mode=mode, + fields=fields, + range_element_type=range_element_type, + ) class Test_scalar_field_to_json(unittest.TestCase): @@ -1251,6 +1263,98 @@ def test_w_dict_unknown_fields(self): ) +class Test_range_field_to_json(unittest.TestCase): + def _call_fut(self, field, value): + from google.cloud.bigquery._helpers import _range_field_to_json + + return _range_field_to_json(field, value) + + def test_w_date(self): + field = _make_field("RANGE", range_element_type="DATE") + start = datetime.date(2016, 12, 3) + original = {"start": start} + converted = self._call_fut(field.range_element_type, original) + expected = {"start": "2016-12-03", "end": None} + self.assertEqual(converted, expected) + + def test_w_date_string(self): + field = _make_field("RANGE", range_element_type="DATE") + original = {"start": "2016-12-03"} + converted = self._call_fut(field.range_element_type, original) + expected = {"start": "2016-12-03", "end": None} + self.assertEqual(converted, expected) + + def test_w_datetime(self): + field = _make_field("RANGE", range_element_type="DATETIME") + start = datetime.datetime(2016, 12, 3, 14, 11, 27, 123456) + original = {"start": start} + converted = self._call_fut(field.range_element_type, original) + expected = {"start": "2016-12-03T14:11:27.123456", "end": None} + self.assertEqual(converted, expected) + + def test_w_datetime_string(self): + field = _make_field("RANGE", range_element_type="DATETIME") + original = {"start": "2016-12-03T14:11:27.123456"} + converted = self._call_fut(field.range_element_type, original) + expected = {"start": "2016-12-03T14:11:27.123456", "end": None} + self.assertEqual(converted, expected) + + def test_w_timestamp(self): + from google.cloud._helpers import UTC + + field = _make_field("RANGE", range_element_type="TIMESTAMP") + start = datetime.datetime(2016, 12, 3, 14, 11, 27, 123456, tzinfo=UTC) + original = {"start": start} + converted = self._call_fut(field.range_element_type, original) + expected = {"start": "2016-12-03T14:11:27.123456Z", "end": None} + self.assertEqual(converted, expected) + + def test_w_timestamp_string(self): + field = _make_field("RANGE", range_element_type="TIMESTAMP") + original = {"start": "2016-12-03T14:11:27.123456Z"} + converted = self._call_fut(field.range_element_type, original) + expected = {"start": "2016-12-03T14:11:27.123456Z", "end": None} + self.assertEqual(converted, expected) + + def test_w_timestamp_float(self): + field = _make_field("RANGE", range_element_type="TIMESTAMP") + original = {"start": 12.34567} + converted = self._call_fut(field.range_element_type, original) + expected = {"start": 12.34567, "end": None} + self.assertEqual(converted, expected) + + def test_w_string_literal(self): + field = _make_field("RANGE", range_element_type="DATE") + original = "[2016-12-03, UNBOUNDED)" + converted = self._call_fut(field.range_element_type, original) + expected = {"start": "2016-12-03", "end": None} + self.assertEqual(converted, expected) + + def test_w_unsupported_range_element_type(self): + field = _make_field("RANGE", range_element_type="TIME") + with self.assertRaises(ValueError): + self._call_fut( + field.range_element_type, + {"start": datetime.time(12, 13, 41)}, + ) + + def test_w_no_range_element_type(self): + field = _make_field("RANGE") + with self.assertRaises(ValueError): + self._call_fut(field.range_element_type, "2016-12-03") + + def test_w_incorrect_literal_format(self): + field = _make_field("RANGE", range_element_type="DATE") + original = "[2016-12-03, UNBOUNDED]" + with self.assertRaises(ValueError): + self._call_fut(field.range_element_type, original) + + def test_w_unsupported_representation(self): + field = _make_field("RANGE", range_element_type="DATE") + with self.assertRaises(ValueError): + self._call_fut(field.range_element_type, object()) + + class Test_field_to_json(unittest.TestCase): def _call_fut(self, field, value): from google.cloud.bigquery._helpers import _field_to_json @@ -1285,6 +1389,12 @@ def test_w_scalar(self): converted = self._call_fut(field, original) self.assertEqual(converted, str(original)) + def test_w_range(self): + field = _make_field("RANGE", range_element_type="DATE") + original = {"start": "2016-12-03", "end": "2024-12-03"} + converted = self._call_fut(field, original) + self.assertEqual(converted, original) + class Test_snake_to_camel_case(unittest.TestCase): def _call_fut(self, value): From a86d7b96813f67fea28b46c5252416222edca9a6 Mon Sep 17 00:00:00 2001 From: Lingqing Gan Date: Thu, 9 May 2024 11:42:19 -0700 Subject: [PATCH 2/6] fix: add pyarrow version check for range support (#1914) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add pyarrow version check for range support * add comment why we are making a separate constant --------- Co-authored-by: Tim Sweña (Swast) --- google/cloud/bigquery/_versions_helpers.py | 14 +++++++ google/cloud/bigquery/table.py | 48 +++++++--------------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/google/cloud/bigquery/_versions_helpers.py b/google/cloud/bigquery/_versions_helpers.py index 50d5961b3..72d4c921d 100644 --- a/google/cloud/bigquery/_versions_helpers.py +++ b/google/cloud/bigquery/_versions_helpers.py @@ -26,6 +26,9 @@ _BQ_STORAGE_OPTIONAL_READ_SESSION_VERSION = packaging.version.Version("2.6.0") _MIN_PANDAS_VERSION = packaging.version.Version("1.1.0") +_MIN_PANDAS_VERSION_RANGE = packaging.version.Version("1.5.0") +_MIN_PYARROW_VERSION_RANGE = packaging.version.Version("10.0.1") + class PyarrowVersions: """Version comparisons for pyarrow package.""" @@ -234,3 +237,14 @@ def try_import(self, raise_if_error: bool = False) -> Any: PANDAS_VERSIONS = PandasVersions() + +# Since RANGE support in pandas requires specific versions +# of both pyarrow and pandas, we make this a separate +# constant instead of as a property of PANDAS_VERSIONS +# or PYARROW_VERSIONS. +SUPPORTS_RANGE_PYARROW = ( + PANDAS_VERSIONS.try_import() is not None + and PANDAS_VERSIONS.installed_version >= _MIN_PANDAS_VERSION_RANGE + and PYARROW_VERSIONS.try_import() is not None + and PYARROW_VERSIONS.installed_version >= _MIN_PYARROW_VERSION_RANGE +) diff --git a/google/cloud/bigquery/table.py b/google/cloud/bigquery/table.py index 2f07bcc78..ad1253195 100644 --- a/google/cloud/bigquery/table.py +++ b/google/cloud/bigquery/table.py @@ -100,6 +100,12 @@ "because the necessary `__from_arrow__` attribute is missing." ) +_RANGE_PYARROW_WARNING = ( + "Unable to represent RANGE schema as struct using pandas ArrowDtype. Using " + "`object` instead. To use ArrowDtype, use pandas >= 1.5 and " + "pyarrow >= 10.0.1." +) + # How many of the total rows need to be downloaded already for us to skip # calling the BQ Storage API? ALMOST_COMPLETELY_CACHED_RATIO = 0.333 @@ -2279,26 +2285,18 @@ def to_dataframe( time_dtype = db_dtypes.TimeDtype() if range_date_dtype is DefaultPandasDTypes.RANGE_DATE_DTYPE: - try: + if _versions_helpers.SUPPORTS_RANGE_PYARROW: range_date_dtype = pandas.ArrowDtype( pyarrow.struct( [("start", pyarrow.date32()), ("end", pyarrow.date32())] ) ) - except AttributeError: - # pandas.ArrowDtype was introduced in pandas 1.5, but python 3.7 - # only supports upto pandas 1.3. If pandas.ArrowDtype is not - # present, we raise a warning and set range_date_dtype to None. - msg = ( - "Unable to find class ArrowDtype in pandas, setting " - "range_date_dtype to be None. To use ArrowDtype, please " - "use pandas >= 1.5 and python >= 3.8." - ) - warnings.warn(msg) + else: + warnings.warn(_RANGE_PYARROW_WARNING) range_date_dtype = None if range_datetime_dtype is DefaultPandasDTypes.RANGE_DATETIME_DTYPE: - try: + if _versions_helpers.SUPPORTS_RANGE_PYARROW: range_datetime_dtype = pandas.ArrowDtype( pyarrow.struct( [ @@ -2307,20 +2305,12 @@ def to_dataframe( ] ) ) - except AttributeError: - # pandas.ArrowDtype was introduced in pandas 1.5, but python 3.7 - # only supports upto pandas 1.3. If pandas.ArrowDtype is not - # present, we raise a warning and set range_datetime_dtype to None. - msg = ( - "Unable to find class ArrowDtype in pandas, setting " - "range_datetime_dtype to be None. To use ArrowDtype, " - "please use pandas >= 1.5 and python >= 3.8." - ) - warnings.warn(msg) + else: + warnings.warn(_RANGE_PYARROW_WARNING) range_datetime_dtype = None if range_timestamp_dtype is DefaultPandasDTypes.RANGE_TIMESTAMP_DTYPE: - try: + if _versions_helpers.SUPPORTS_RANGE_PYARROW: range_timestamp_dtype = pandas.ArrowDtype( pyarrow.struct( [ @@ -2329,16 +2319,8 @@ def to_dataframe( ] ) ) - except AttributeError: - # pandas.ArrowDtype was introduced in pandas 1.5, but python 3.7 - # only supports upto pandas 1.3. If pandas.ArrowDtype is not - # present, we raise a warning and set range_timestamp_dtype to None. - msg = ( - "Unable to find class ArrowDtype in pandas, setting " - "range_timestamp_dtype to be None. To use ArrowDtype, " - "please use pandas >= 1.5 and python >= 3.8." - ) - warnings.warn(msg) + else: + warnings.warn(_RANGE_PYARROW_WARNING) range_timestamp_dtype = None if bool_dtype is not None and not hasattr(bool_dtype, "__from_arrow__"): From b739596f37b8c00b375cc811c316b618097d761a Mon Sep 17 00:00:00 2001 From: Chalmer Lowe Date: Wed, 15 May 2024 07:54:36 -0400 Subject: [PATCH 3/6] fix: edit presubmit for to simplify configuration (#1915) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add new presubmit for test purposes * add additional sessions * Update .kokoro/presubmit/presubmit-2.cfg * Update .kokoro/presubmit/presubmit-2.cfg * added timer to nox sessions * Update .kokoro/presubmit/presubmit-2.cfg * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * removes references to most environment variables * testing the use of base names for the nox sessions * removes references to unneeded linting and typing env variables * change file name and update env_vars in presubmit-2 * remove timed decorators * revert several files * Update noxfile.py * remove test, remove unneeded vars, etc --------- Co-authored-by: Owl Bot --- .kokoro/presubmit/presubmit.cfg | 12 ++---------- noxfile.py | 32 -------------------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/.kokoro/presubmit/presubmit.cfg b/.kokoro/presubmit/presubmit.cfg index fa39b1118..ce3953120 100644 --- a/.kokoro/presubmit/presubmit.cfg +++ b/.kokoro/presubmit/presubmit.cfg @@ -2,14 +2,6 @@ # Disable system tests. env_vars: { - key: "RUN_SYSTEM_TESTS" - value: "false" -} -env_vars: { - key: "RUN_SNIPPETS_TESTS" - value: "false" -} -env_vars: { - key: "RUN_LINTING_TYPING_TESTS" - value: "false" + key: "NOX_SESSION" + value: "unit_noextras unit cover docs" } diff --git a/noxfile.py b/noxfile.py index 78a9ab5b6..02655a7b7 100644 --- a/noxfile.py +++ b/noxfile.py @@ -132,10 +132,6 @@ def unit_noextras(session): def mypy(session): """Run type checks with mypy.""" - # Check the value of `RUN_LINTING_TYPING_TESTS` env var. It defaults to true. - if os.environ.get("RUN_LINTING_TYPING_TESTS", "true") == "false": - session.skip("RUN_LINTING_TYPING_TESTS is set to false, skipping") - session.install("-e", ".[all]") session.install(MYPY_VERSION) @@ -157,10 +153,6 @@ def pytype(session): # recent version avoids the error until a possibly better fix is found. # https://github.com/googleapis/python-bigquery/issues/655 - # Check the value of `RUN_LINTING_TYPING_TESTS` env var. It defaults to true. - if os.environ.get("RUN_LINTING_TYPING_TESTS", "true") == "false": - session.skip("RUN_LINTING_TYPING_TESTS is set to false, skipping") - session.install("attrs==20.3.0") session.install("-e", ".[all]") session.install(PYTYPE_VERSION) @@ -176,10 +168,6 @@ def system(session): CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" ) - # Check the value of `RUN_SYSTEM_TESTS` env var. It defaults to true. - if os.environ.get("RUN_SYSTEM_TESTS", "true") == "false": - session.skip("RUN_SYSTEM_TESTS is set to false, skipping") - # Sanity check: Only run system tests if the environment variable is set. if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): session.skip("Credentials must be set via environment variable.") @@ -224,10 +212,6 @@ def system(session): def mypy_samples(session): """Run type checks with mypy.""" - # Check the value of `RUN_LINTING_TYPING_TESTS` env var. It defaults to true. - if os.environ.get("RUN_LINTING_TYPING_TESTS", "true") == "false": - session.skip("RUN_LINTING_TYPING_TESTS is set to false, skipping") - session.install("pytest") for requirements_path in CURRENT_DIRECTORY.glob("samples/*/requirements.txt"): session.install("-r", str(requirements_path)) @@ -263,10 +247,6 @@ def mypy_samples(session): def snippets(session): """Run the snippets test suite.""" - # Check the value of `RUN_SNIPPETS_TESTS` env var. It defaults to true. - if os.environ.get("RUN_SNIPPETS_TESTS", "true") == "false": - session.skip("RUN_SNIPPETS_TESTS is set to false, skipping") - constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" ) @@ -409,10 +389,6 @@ def lint(session): serious code quality issues. """ - # Check the value of `RUN_LINTING_TYPING_TESTS` env var. It defaults to true. - if os.environ.get("RUN_LINTING_TYPING_TESTS", "true") == "false": - session.skip("RUN_LINTING_TYPING_TESTS is set to false, skipping") - session.install("flake8", BLACK_VERSION) session.install("-e", ".") session.run("flake8", os.path.join("google", "cloud", "bigquery")) @@ -427,10 +403,6 @@ def lint(session): def lint_setup_py(session): """Verify that setup.py is valid (including RST check).""" - # Check the value of `RUN_LINTING_TYPING_TESTS` env var. It defaults to true. - if os.environ.get("RUN_LINTING_TYPING_TESTS", "true") == "false": - session.skip("RUN_LINTING_TYPING_TESTS is set to false, skipping") - session.install("docutils", "Pygments") session.run("python", "setup.py", "check", "--restructuredtext", "--strict") @@ -441,10 +413,6 @@ def blacken(session): Format code to uniform standard. """ - # Check the value of `RUN_LINTING_TYPING_TESTS` env var. It defaults to true. - if os.environ.get("RUN_LINTING_TYPING_TESTS", "true") == "false": - session.skip("RUN_LINTING_TYPING_TESTS is set to false, skipping") - session.install(BLACK_VERSION) session.run("black", *BLACK_PATHS) From ea750e0248473b6207b8517aa7ea1cf4e19bccf2 Mon Sep 17 00:00:00 2001 From: Chalmer Lowe Date: Thu, 16 May 2024 08:02:36 -0400 Subject: [PATCH 4/6] feat: adds timer decorator to facilitate debugging (#1917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: adds timer decorator to sessions * updates _calculate_duration function * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot --- noxfile.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/noxfile.py b/noxfile.py index 02655a7b7..5f88e46a0 100644 --- a/noxfile.py +++ b/noxfile.py @@ -14,11 +14,13 @@ from __future__ import absolute_import +from functools import wraps import pathlib import os import re import shutil import nox +import time MYPY_VERSION = "mypy==1.6.1" @@ -40,6 +42,27 @@ UNIT_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.12"] CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() + +def _calculate_duration(func): + """This decorator prints the execution time for the decorated function.""" + + @wraps(func) + def wrapper(*args, **kwargs): + start = time.monotonic() + result = func(*args, **kwargs) + end = time.monotonic() + total_seconds = round(end - start) + hours = total_seconds // 3600 # Integer division to get hours + remaining_seconds = total_seconds % 3600 # Modulo to find remaining seconds + minutes = remaining_seconds // 60 + seconds = remaining_seconds % 60 + human_time = f"{hours:}:{minutes:0>2}:{seconds:0>2}" + print(f"Session ran in {total_seconds} seconds ({human_time})") + return result + + return wrapper + + # 'docfx' is excluded since it only needs to run in 'docs-presubmit' nox.options.sessions = [ "unit_noextras", @@ -105,6 +128,7 @@ def default(session, install_extras=True): @nox.session(python=UNIT_TEST_PYTHON_VERSIONS) +@_calculate_duration def unit(session): """Run the unit test suite.""" @@ -112,6 +136,7 @@ def unit(session): @nox.session(python=[UNIT_TEST_PYTHON_VERSIONS[0], UNIT_TEST_PYTHON_VERSIONS[-1]]) +@_calculate_duration def unit_noextras(session): """Run the unit test suite.""" @@ -129,6 +154,7 @@ def unit_noextras(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def mypy(session): """Run type checks with mypy.""" @@ -147,6 +173,7 @@ def mypy(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def pytype(session): """Run type checks with pytype.""" # An indirect dependecy attrs==21.1.0 breaks the check, and installing a less @@ -161,6 +188,7 @@ def pytype(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) +@_calculate_duration def system(session): """Run the system test suite.""" @@ -209,6 +237,7 @@ def system(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def mypy_samples(session): """Run type checks with mypy.""" @@ -244,6 +273,7 @@ def mypy_samples(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) +@_calculate_duration def snippets(session): """Run the snippets test suite.""" @@ -279,6 +309,7 @@ def snippets(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def cover(session): """Run the final coverage report. @@ -292,6 +323,7 @@ def cover(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) +@_calculate_duration def prerelease_deps(session): """Run all tests with prerelease versions of dependencies installed. @@ -382,6 +414,7 @@ def prerelease_deps(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def lint(session): """Run linters. @@ -400,6 +433,7 @@ def lint(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def lint_setup_py(session): """Verify that setup.py is valid (including RST check).""" @@ -408,6 +442,7 @@ def lint_setup_py(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def blacken(session): """Run black. Format code to uniform standard. @@ -418,6 +453,7 @@ def blacken(session): @nox.session(python="3.9") +@_calculate_duration def docs(session): """Build the docs.""" @@ -454,6 +490,7 @@ def docs(session): @nox.session(python="3.10") +@_calculate_duration def docfx(session): """Build the docfx yaml files for this library.""" From 01fc0ef9341c3d31bc61e069e599c498242893fc Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 16 May 2024 17:29:02 +0200 Subject: [PATCH 5/6] chore(deps): update all dependencies (#1916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update all dependencies * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * Update samples/geography/requirements.txt --------- Co-authored-by: Owl Bot Co-authored-by: Chalmer Lowe --- samples/desktopapp/requirements-test.txt | 2 +- samples/desktopapp/requirements.txt | 2 +- samples/geography/requirements-test.txt | 2 +- samples/geography/requirements.txt | 13 +++++++------ samples/magics/requirements-test.txt | 2 +- samples/magics/requirements.txt | 4 ++-- samples/notebooks/requirements-test.txt | 2 +- samples/notebooks/requirements.txt | 4 ++-- samples/snippets/requirements-test.txt | 2 +- samples/snippets/requirements.txt | 2 +- 10 files changed, 18 insertions(+), 17 deletions(-) diff --git a/samples/desktopapp/requirements-test.txt b/samples/desktopapp/requirements-test.txt index 9142d4905..4487e2ef3 100644 --- a/samples/desktopapp/requirements-test.txt +++ b/samples/desktopapp/requirements-test.txt @@ -1,4 +1,4 @@ google-cloud-testutils==1.4.0 pytest===7.4.4; python_version == '3.7' -pytest==8.1.1; python_version >= '3.8' +pytest==8.2.0; python_version >= '3.8' mock==5.1.0 diff --git a/samples/desktopapp/requirements.txt b/samples/desktopapp/requirements.txt index 3e9e59430..716f088ac 100644 --- a/samples/desktopapp/requirements.txt +++ b/samples/desktopapp/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-bigquery==3.21.0 +google-cloud-bigquery==3.22.0 google-auth-oauthlib==1.2.0 diff --git a/samples/geography/requirements-test.txt b/samples/geography/requirements-test.txt index f052969d3..3689fda4e 100644 --- a/samples/geography/requirements-test.txt +++ b/samples/geography/requirements-test.txt @@ -1,3 +1,3 @@ pytest===7.4.4; python_version == '3.7' -pytest==8.1.1; python_version >= '3.8' +pytest==8.2.0; python_version >= '3.8' mock==5.1.0 diff --git a/samples/geography/requirements.txt b/samples/geography/requirements.txt index 6502ba146..8c268759e 100644 --- a/samples/geography/requirements.txt +++ b/samples/geography/requirements.txt @@ -12,16 +12,17 @@ Fiona==1.9.6 geojson==3.1.0 geopandas===0.10.2; python_version == '3.7' geopandas===0.13.2; python_version == '3.8' -geopandas==0.14.3; python_version >= '3.9' -google-api-core==2.18.0 +geopandas==0.14.4; python_version >= '3.9' +google-api-core==2.19.0 google-auth==2.29.0 -google-cloud-bigquery==3.21.0 -google-cloud-bigquery-storage==2.24.0 +google-cloud-bigquery==3.22.0 +google-cloud-bigquery-storage==2.25.0 google-cloud-core==2.4.1 google-crc32c==1.5.0 google-resumable-media==2.7.0 googleapis-common-protos==1.63.0 -grpcio==1.62.2 +grpcio==1.62.2; python_version == '3.7' +grpcio==1.63.0; python_version >= '3.8' idna==3.7 munch==4.0.0 mypy-extensions==1.0.0 @@ -31,7 +32,7 @@ pandas===2.0.3; python_version == '3.8' pandas==2.2.2; python_version >= '3.9' proto-plus==1.23.0 pyarrow==12.0.1; python_version == '3.7' -pyarrow==15.0.2; python_version >= '3.8' +pyarrow==16.0.0; python_version >= '3.8' pyasn1===0.5.1; python_version == '3.7' pyasn1==0.6.0; python_version >= '3.8' pyasn1-modules===0.3.0; python_version == '3.7' diff --git a/samples/magics/requirements-test.txt b/samples/magics/requirements-test.txt index 9142d4905..4487e2ef3 100644 --- a/samples/magics/requirements-test.txt +++ b/samples/magics/requirements-test.txt @@ -1,4 +1,4 @@ google-cloud-testutils==1.4.0 pytest===7.4.4; python_version == '3.7' -pytest==8.1.1; python_version >= '3.8' +pytest==8.2.0; python_version >= '3.8' mock==5.1.0 diff --git a/samples/magics/requirements.txt b/samples/magics/requirements.txt index a431f466f..67be479e1 100644 --- a/samples/magics/requirements.txt +++ b/samples/magics/requirements.txt @@ -1,6 +1,6 @@ db-dtypes==1.2.0 -google.cloud.bigquery==3.21.0 -google-cloud-bigquery-storage==2.24.0 +google.cloud.bigquery==3.22.0 +google-cloud-bigquery-storage==2.25.0 ipython===7.31.1; python_version == '3.7' ipython===8.0.1; python_version == '3.8' ipython===8.18.1; python_version >= '3.9' diff --git a/samples/notebooks/requirements-test.txt b/samples/notebooks/requirements-test.txt index 9142d4905..4487e2ef3 100644 --- a/samples/notebooks/requirements-test.txt +++ b/samples/notebooks/requirements-test.txt @@ -1,4 +1,4 @@ google-cloud-testutils==1.4.0 pytest===7.4.4; python_version == '3.7' -pytest==8.1.1; python_version >= '3.8' +pytest==8.2.0; python_version >= '3.8' mock==5.1.0 diff --git a/samples/notebooks/requirements.txt b/samples/notebooks/requirements.txt index dcce1e3ec..a60175de5 100644 --- a/samples/notebooks/requirements.txt +++ b/samples/notebooks/requirements.txt @@ -1,6 +1,6 @@ db-dtypes==1.2.0 -google-cloud-bigquery==3.21.0 -google-cloud-bigquery-storage==2.24.0 +google-cloud-bigquery==3.22.0 +google-cloud-bigquery-storage==2.25.0 ipython===7.31.1; python_version == '3.7' ipython===8.0.1; python_version == '3.8' ipython===8.18.1; python_version >= '3.9' diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt index 0343ab89a..3c8fcc27d 100644 --- a/samples/snippets/requirements-test.txt +++ b/samples/snippets/requirements-test.txt @@ -1,5 +1,5 @@ # samples/snippets should be runnable with no "extras" google-cloud-testutils==1.4.0 pytest===7.4.4; python_version == '3.7' -pytest==8.1.1; python_version >= '3.8' +pytest==8.2.0; python_version >= '3.8' mock==5.1.0 diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index fee0ce65a..a5e90118f 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,2 +1,2 @@ # samples/snippets should be runnable with no "extras" -google-cloud-bigquery==3.21.0 +google-cloud-bigquery==3.22.0 From a429e8fd997a8850d15d434089869cf24e53c9e6 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 13:04:08 -0400 Subject: [PATCH 6/6] chore(main): release 3.23.0 (#1911) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: Chalmer Lowe --- CHANGELOG.md | 14 ++++++++++++++ google/cloud/bigquery/version.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a201ef851..804c0ae1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ [1]: https://pypi.org/project/google-cloud-bigquery/#history +## [3.23.0](https://github.com/googleapis/python-bigquery/compare/v3.22.0...v3.23.0) (2024-05-16) + + +### Features + +* Adds timer decorator to facilitate debugging ([#1917](https://github.com/googleapis/python-bigquery/issues/1917)) ([ea750e0](https://github.com/googleapis/python-bigquery/commit/ea750e0248473b6207b8517aa7ea1cf4e19bccf2)) +* Support insertAll for range ([#1909](https://github.com/googleapis/python-bigquery/issues/1909)) ([74e75e8](https://github.com/googleapis/python-bigquery/commit/74e75e89ce3a5ac18112b2c1c33248445ff072e4)) + + +### Bug Fixes + +* Add pyarrow version check for range support ([#1914](https://github.com/googleapis/python-bigquery/issues/1914)) ([a86d7b9](https://github.com/googleapis/python-bigquery/commit/a86d7b96813f67fea28b46c5252416222edca9a6)) +* Edit presubmit for to simplify configuration ([#1915](https://github.com/googleapis/python-bigquery/issues/1915)) ([b739596](https://github.com/googleapis/python-bigquery/commit/b739596f37b8c00b375cc811c316b618097d761a)) + ## [3.22.0](https://github.com/googleapis/python-bigquery/compare/v3.21.0...v3.22.0) (2024-04-19) diff --git a/google/cloud/bigquery/version.py b/google/cloud/bigquery/version.py index b6c082ffc..0938c08f6 100644 --- a/google/cloud/bigquery/version.py +++ b/google/cloud/bigquery/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "3.22.0" +__version__ = "3.23.0"