Skip to content

Commit 584bbd9

Browse files
authored
Merge branch 'main' into feat/expose-cursor-query-job
2 parents b9e2903 + a2520ca commit 584bbd9

File tree

15 files changed

+974
-356
lines changed

15 files changed

+974
-356
lines changed

.github/.OwlBot.lock.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# limitations under the License.
1414
docker:
1515
image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest
16-
digest: sha256:8555f0e37e6261408f792bfd6635102d2da5ad73f8f09bcb24f25e6afb5fac97
16+
digest: sha256:2e247c7bf5154df7f98cce087a20ca7605e236340c7d6d1a14447e5c06791bd6

.kokoro/requirements.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ typing-extensions
55
twine
66
wheel
77
setuptools
8-
nox
8+
nox>=2022.11.21 # required to remove dependency on py
99
charset-normalizer<3
1010
click<8.1.0

.kokoro/requirements.txt

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#
2-
# This file is autogenerated by pip-compile with python 3.10
3-
# To update, run:
2+
# This file is autogenerated by pip-compile with Python 3.9
3+
# by the following command:
44
#
55
# pip-compile --allow-unsafe --generate-hashes requirements.in
66
#
@@ -335,9 +335,9 @@ more-itertools==9.0.0 \
335335
--hash=sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41 \
336336
--hash=sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab
337337
# via jaraco-classes
338-
nox==2022.8.7 \
339-
--hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \
340-
--hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c
338+
nox==2022.11.21 \
339+
--hash=sha256:0e41a990e290e274cb205a976c4c97ee3c5234441a8132c8c3fd9ea3c22149eb \
340+
--hash=sha256:e21c31de0711d1274ca585a2c5fde36b1aa962005ba8e9322bf5eeed16dcd684
341341
# via -r requirements.in
342342
packaging==21.3 \
343343
--hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
@@ -380,10 +380,6 @@ protobuf==3.20.3 \
380380
# gcp-docuploader
381381
# gcp-releasetool
382382
# google-api-core
383-
py==1.11.0 \
384-
--hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
385-
--hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
386-
# via nox
387383
pyasn1==0.4.8 \
388384
--hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \
389385
--hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@
55
[1]: https://pypi.org/project/google-cloud-bigquery/#history
66

77

8+
## [3.7.0](https://github.com/googleapis/python-bigquery/compare/v3.6.0...v3.7.0) (2023-03-06)
9+
10+
11+
### Features
12+
13+
* Add `connection_properties` and `create_session` to `LoadJobConfig` ([#1509](https://github.com/googleapis/python-bigquery/issues/1509)) ([cd0aaa1](https://github.com/googleapis/python-bigquery/commit/cd0aaa15960e9ca7a0aaf411c8e4990f95421816))
14+
* Add default_query_job_config property and property setter to BQ client ([#1511](https://github.com/googleapis/python-bigquery/issues/1511)) ([a23092c](https://github.com/googleapis/python-bigquery/commit/a23092cad834c6a016f455d46fefa13bb6cdbf0f))
15+
16+
17+
### Documentation
18+
19+
* Remove &lt; 3.11 reference from README ([#1502](https://github.com/googleapis/python-bigquery/issues/1502)) ([c7417f4](https://github.com/googleapis/python-bigquery/commit/c7417f43563e20a3e6f1a57f46925fb274b28b07))
20+
821
## [3.6.0](https://github.com/googleapis/python-bigquery/compare/v3.5.0...v3.6.0) (2023-02-22)
922

1023

google/cloud/bigquery/client.py

+72-58
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ class Client(ClientWithProject):
210210
default_query_job_config (Optional[google.cloud.bigquery.job.QueryJobConfig]):
211211
Default ``QueryJobConfig``.
212212
Will be merged into job configs passed into the ``query`` method.
213+
default_load_job_config (Optional[google.cloud.bigquery.job.LoadJobConfig]):
214+
Default ``LoadJobConfig``.
215+
Will be merged into job configs passed into the ``load_table_*`` methods.
213216
client_info (Optional[google.api_core.client_info.ClientInfo]):
214217
The client info used to send a user-agent string along with API
215218
requests. If ``None``, then default info will be used. Generally,
@@ -235,6 +238,7 @@ def __init__(
235238
_http=None,
236239
location=None,
237240
default_query_job_config=None,
241+
default_load_job_config=None,
238242
client_info=None,
239243
client_options=None,
240244
) -> None:
@@ -260,6 +264,7 @@ def __init__(
260264
self._connection = Connection(self, **kw_args)
261265
self._location = location
262266
self._default_query_job_config = copy.deepcopy(default_query_job_config)
267+
self._default_load_job_config = copy.deepcopy(default_load_job_config)
263268

264269
@property
265270
def location(self):
@@ -277,6 +282,17 @@ def default_query_job_config(self):
277282
def default_query_job_config(self, value: QueryJobConfig):
278283
self._default_query_job_config = copy.deepcopy(value)
279284

285+
@property
286+
def default_load_job_config(self):
287+
"""Default ``LoadJobConfig``.
288+
Will be merged into job configs passed into the ``load_table_*`` methods.
289+
"""
290+
return self._default_load_job_config
291+
292+
@default_load_job_config.setter
293+
def default_load_job_config(self, value: LoadJobConfig):
294+
self._default_load_job_config = copy.deepcopy(value)
295+
280296
def close(self):
281297
"""Close the underlying transport objects, releasing system resources.
282298
@@ -1976,15 +1992,8 @@ def create_job(
19761992
)
19771993
destination = _get_sub_prop(job_config, ["copy", "destinationTable"])
19781994
destination = TableReference.from_api_repr(destination)
1979-
sources = []
1980-
source_configs = _get_sub_prop(job_config, ["copy", "sourceTables"])
1981-
if source_configs is None:
1982-
source_configs = [_get_sub_prop(job_config, ["copy", "sourceTable"])]
1983-
for source_config in source_configs:
1984-
table_ref = TableReference.from_api_repr(source_config)
1985-
sources.append(table_ref)
19861995
return self.copy_table(
1987-
sources,
1996+
[], # Source table(s) already in job_config resource.
19881997
destination,
19891998
job_config=typing.cast(CopyJobConfig, copy_job_config),
19901999
retry=retry,
@@ -2337,8 +2346,8 @@ def load_table_from_uri(
23372346
23382347
Raises:
23392348
TypeError:
2340-
If ``job_config`` is not an instance of :class:`~google.cloud.bigquery.job.LoadJobConfig`
2341-
class.
2349+
If ``job_config`` is not an instance of
2350+
:class:`~google.cloud.bigquery.job.LoadJobConfig` class.
23422351
"""
23432352
job_id = _make_job_id(job_id, job_id_prefix)
23442353

@@ -2355,11 +2364,14 @@ def load_table_from_uri(
23552364

23562365
destination = _table_arg_to_table_ref(destination, default_project=self.project)
23572366

2358-
if job_config:
2359-
job_config = copy.deepcopy(job_config)
2360-
_verify_job_config_type(job_config, google.cloud.bigquery.job.LoadJobConfig)
2367+
if job_config is not None:
2368+
_verify_job_config_type(job_config, LoadJobConfig)
2369+
else:
2370+
job_config = job.LoadJobConfig()
23612371

2362-
load_job = job.LoadJob(job_ref, source_uris, destination, self, job_config)
2372+
new_job_config = job_config._fill_from_default(self._default_load_job_config)
2373+
2374+
load_job = job.LoadJob(job_ref, source_uris, destination, self, new_job_config)
23632375
load_job._begin(retry=retry, timeout=timeout)
23642376

23652377
return load_job
@@ -2431,8 +2443,8 @@ def load_table_from_file(
24312443
mode.
24322444
24332445
TypeError:
2434-
If ``job_config`` is not an instance of :class:`~google.cloud.bigquery.job.LoadJobConfig`
2435-
class.
2446+
If ``job_config`` is not an instance of
2447+
:class:`~google.cloud.bigquery.job.LoadJobConfig` class.
24362448
"""
24372449
job_id = _make_job_id(job_id, job_id_prefix)
24382450

@@ -2444,10 +2456,15 @@ def load_table_from_file(
24442456

24452457
destination = _table_arg_to_table_ref(destination, default_project=self.project)
24462458
job_ref = job._JobReference(job_id, project=project, location=location)
2447-
if job_config:
2448-
job_config = copy.deepcopy(job_config)
2449-
_verify_job_config_type(job_config, google.cloud.bigquery.job.LoadJobConfig)
2450-
load_job = job.LoadJob(job_ref, None, destination, self, job_config)
2459+
2460+
if job_config is not None:
2461+
_verify_job_config_type(job_config, LoadJobConfig)
2462+
else:
2463+
job_config = job.LoadJobConfig()
2464+
2465+
new_job_config = job_config._fill_from_default(self._default_load_job_config)
2466+
2467+
load_job = job.LoadJob(job_ref, None, destination, self, new_job_config)
24512468
job_resource = load_job.to_api_repr()
24522469

24532470
if rewind:
@@ -2571,43 +2588,40 @@ def load_table_from_dataframe(
25712588
If a usable parquet engine cannot be found. This method
25722589
requires :mod:`pyarrow` to be installed.
25732590
TypeError:
2574-
If ``job_config`` is not an instance of :class:`~google.cloud.bigquery.job.LoadJobConfig`
2575-
class.
2591+
If ``job_config`` is not an instance of
2592+
:class:`~google.cloud.bigquery.job.LoadJobConfig` class.
25762593
"""
25772594
job_id = _make_job_id(job_id, job_id_prefix)
25782595

2579-
if job_config:
2580-
_verify_job_config_type(job_config, google.cloud.bigquery.job.LoadJobConfig)
2581-
# Make a copy so that the job config isn't modified in-place.
2582-
job_config_properties = copy.deepcopy(job_config._properties)
2583-
job_config = job.LoadJobConfig()
2584-
job_config._properties = job_config_properties
2585-
2596+
if job_config is not None:
2597+
_verify_job_config_type(job_config, LoadJobConfig)
25862598
else:
25872599
job_config = job.LoadJobConfig()
25882600

2601+
new_job_config = job_config._fill_from_default(self._default_load_job_config)
2602+
25892603
supported_formats = {job.SourceFormat.CSV, job.SourceFormat.PARQUET}
2590-
if job_config.source_format is None:
2604+
if new_job_config.source_format is None:
25912605
# default value
2592-
job_config.source_format = job.SourceFormat.PARQUET
2606+
new_job_config.source_format = job.SourceFormat.PARQUET
25932607

25942608
if (
2595-
job_config.source_format == job.SourceFormat.PARQUET
2596-
and job_config.parquet_options is None
2609+
new_job_config.source_format == job.SourceFormat.PARQUET
2610+
and new_job_config.parquet_options is None
25972611
):
25982612
parquet_options = ParquetOptions()
25992613
# default value
26002614
parquet_options.enable_list_inference = True
2601-
job_config.parquet_options = parquet_options
2615+
new_job_config.parquet_options = parquet_options
26022616

2603-
if job_config.source_format not in supported_formats:
2617+
if new_job_config.source_format not in supported_formats:
26042618
raise ValueError(
26052619
"Got unexpected source_format: '{}'. Currently, only PARQUET and CSV are supported".format(
2606-
job_config.source_format
2620+
new_job_config.source_format
26072621
)
26082622
)
26092623

2610-
if pyarrow is None and job_config.source_format == job.SourceFormat.PARQUET:
2624+
if pyarrow is None and new_job_config.source_format == job.SourceFormat.PARQUET:
26112625
# pyarrow is now the only supported parquet engine.
26122626
raise ValueError("This method requires pyarrow to be installed")
26132627

@@ -2618,8 +2632,8 @@ def load_table_from_dataframe(
26182632
# schema, and check if dataframe schema is compatible with it - except
26192633
# for WRITE_TRUNCATE jobs, the existing schema does not matter then.
26202634
if (
2621-
not job_config.schema
2622-
and job_config.write_disposition != job.WriteDisposition.WRITE_TRUNCATE
2635+
not new_job_config.schema
2636+
and new_job_config.write_disposition != job.WriteDisposition.WRITE_TRUNCATE
26232637
):
26242638
try:
26252639
table = self.get_table(destination)
@@ -2630,7 +2644,7 @@ def load_table_from_dataframe(
26302644
name
26312645
for name, _ in _pandas_helpers.list_columns_and_indexes(dataframe)
26322646
)
2633-
job_config.schema = [
2647+
new_job_config.schema = [
26342648
# Field description and policy tags are not needed to
26352649
# serialize a data frame.
26362650
SchemaField(
@@ -2644,11 +2658,11 @@ def load_table_from_dataframe(
26442658
if field.name in columns_and_indexes
26452659
]
26462660

2647-
job_config.schema = _pandas_helpers.dataframe_to_bq_schema(
2648-
dataframe, job_config.schema
2661+
new_job_config.schema = _pandas_helpers.dataframe_to_bq_schema(
2662+
dataframe, new_job_config.schema
26492663
)
26502664

2651-
if not job_config.schema:
2665+
if not new_job_config.schema:
26522666
# the schema could not be fully detected
26532667
warnings.warn(
26542668
"Schema could not be detected for all columns. Loading from a "
@@ -2659,13 +2673,13 @@ def load_table_from_dataframe(
26592673
)
26602674

26612675
tmpfd, tmppath = tempfile.mkstemp(
2662-
suffix="_job_{}.{}".format(job_id[:8], job_config.source_format.lower())
2676+
suffix="_job_{}.{}".format(job_id[:8], new_job_config.source_format.lower())
26632677
)
26642678
os.close(tmpfd)
26652679

26662680
try:
26672681

2668-
if job_config.source_format == job.SourceFormat.PARQUET:
2682+
if new_job_config.source_format == job.SourceFormat.PARQUET:
26692683
if _PYARROW_VERSION in _PYARROW_BAD_VERSIONS:
26702684
msg = (
26712685
"Loading dataframe data in PARQUET format with pyarrow "
@@ -2676,13 +2690,13 @@ def load_table_from_dataframe(
26762690
)
26772691
warnings.warn(msg, category=RuntimeWarning)
26782692

2679-
if job_config.schema:
2693+
if new_job_config.schema:
26802694
if parquet_compression == "snappy": # adjust the default value
26812695
parquet_compression = parquet_compression.upper()
26822696

26832697
_pandas_helpers.dataframe_to_parquet(
26842698
dataframe,
2685-
job_config.schema,
2699+
new_job_config.schema,
26862700
tmppath,
26872701
parquet_compression=parquet_compression,
26882702
parquet_use_compliant_nested_type=True,
@@ -2722,7 +2736,7 @@ def load_table_from_dataframe(
27222736
job_id_prefix=job_id_prefix,
27232737
location=location,
27242738
project=project,
2725-
job_config=job_config,
2739+
job_config=new_job_config,
27262740
timeout=timeout,
27272741
)
27282742

@@ -2798,22 +2812,22 @@ def load_table_from_json(
27982812
27992813
Raises:
28002814
TypeError:
2801-
If ``job_config`` is not an instance of :class:`~google.cloud.bigquery.job.LoadJobConfig`
2802-
class.
2815+
If ``job_config`` is not an instance of
2816+
:class:`~google.cloud.bigquery.job.LoadJobConfig` class.
28032817
"""
28042818
job_id = _make_job_id(job_id, job_id_prefix)
28052819

2806-
if job_config:
2807-
_verify_job_config_type(job_config, google.cloud.bigquery.job.LoadJobConfig)
2808-
# Make a copy so that the job config isn't modified in-place.
2809-
job_config = copy.deepcopy(job_config)
2820+
if job_config is not None:
2821+
_verify_job_config_type(job_config, LoadJobConfig)
28102822
else:
28112823
job_config = job.LoadJobConfig()
28122824

2813-
job_config.source_format = job.SourceFormat.NEWLINE_DELIMITED_JSON
2825+
new_job_config = job_config._fill_from_default(self._default_load_job_config)
2826+
2827+
new_job_config.source_format = job.SourceFormat.NEWLINE_DELIMITED_JSON
28142828

2815-
if job_config.schema is None:
2816-
job_config.autodetect = True
2829+
if new_job_config.schema is None:
2830+
new_job_config.autodetect = True
28172831

28182832
if project is None:
28192833
project = self.project
@@ -2835,7 +2849,7 @@ def load_table_from_json(
28352849
job_id_prefix=job_id_prefix,
28362850
location=location,
28372851
project=project,
2838-
job_config=job_config,
2852+
job_config=new_job_config,
28392853
timeout=timeout,
28402854
)
28412855

0 commit comments

Comments
 (0)