google-cloud-bigquery 3.31.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. google/cloud/bigquery/__init__.py +249 -0
  2. google/cloud/bigquery/_helpers.py +1102 -0
  3. google/cloud/bigquery/_http.py +47 -0
  4. google/cloud/bigquery/_job_helpers.py +600 -0
  5. google/cloud/bigquery/_pandas_helpers.py +1181 -0
  6. google/cloud/bigquery/_pyarrow_helpers.py +147 -0
  7. google/cloud/bigquery/_tqdm_helpers.py +137 -0
  8. google/cloud/bigquery/_versions_helpers.py +264 -0
  9. google/cloud/bigquery/client.py +4406 -0
  10. google/cloud/bigquery/dataset.py +1076 -0
  11. google/cloud/bigquery/dbapi/__init__.py +87 -0
  12. google/cloud/bigquery/dbapi/_helpers.py +522 -0
  13. google/cloud/bigquery/dbapi/connection.py +128 -0
  14. google/cloud/bigquery/dbapi/cursor.py +586 -0
  15. google/cloud/bigquery/dbapi/exceptions.py +58 -0
  16. google/cloud/bigquery/dbapi/types.py +96 -0
  17. google/cloud/bigquery/encryption_configuration.py +84 -0
  18. google/cloud/bigquery/enums.py +389 -0
  19. google/cloud/bigquery/exceptions.py +35 -0
  20. google/cloud/bigquery/external_config.py +1188 -0
  21. google/cloud/bigquery/format_options.py +147 -0
  22. google/cloud/bigquery/iam.py +38 -0
  23. google/cloud/bigquery/job/__init__.py +87 -0
  24. google/cloud/bigquery/job/base.py +1116 -0
  25. google/cloud/bigquery/job/copy_.py +282 -0
  26. google/cloud/bigquery/job/extract.py +271 -0
  27. google/cloud/bigquery/job/load.py +985 -0
  28. google/cloud/bigquery/job/query.py +2498 -0
  29. google/cloud/bigquery/magics/__init__.py +20 -0
  30. google/cloud/bigquery/magics/line_arg_parser/__init__.py +34 -0
  31. google/cloud/bigquery/magics/line_arg_parser/exceptions.py +25 -0
  32. google/cloud/bigquery/magics/line_arg_parser/lexer.py +200 -0
  33. google/cloud/bigquery/magics/line_arg_parser/parser.py +484 -0
  34. google/cloud/bigquery/magics/line_arg_parser/visitors.py +159 -0
  35. google/cloud/bigquery/magics/magics.py +776 -0
  36. google/cloud/bigquery/model.py +517 -0
  37. google/cloud/bigquery/opentelemetry_tracing.py +164 -0
  38. google/cloud/bigquery/py.typed +2 -0
  39. google/cloud/bigquery/query.py +1344 -0
  40. google/cloud/bigquery/retry.py +207 -0
  41. google/cloud/bigquery/routine/__init__.py +33 -0
  42. google/cloud/bigquery/routine/routine.py +744 -0
  43. google/cloud/bigquery/schema.py +896 -0
  44. google/cloud/bigquery/standard_sql.py +389 -0
  45. google/cloud/bigquery/table.py +3594 -0
  46. google/cloud/bigquery/version.py +15 -0
  47. google/cloud/bigquery_v2/__init__.py +56 -0
  48. google/cloud/bigquery_v2/types/__init__.py +54 -0
  49. google/cloud/bigquery_v2/types/encryption_config.py +48 -0
  50. google/cloud/bigquery_v2/types/model.py +1994 -0
  51. google/cloud/bigquery_v2/types/model_reference.py +57 -0
  52. google/cloud/bigquery_v2/types/standard_sql.py +156 -0
  53. google/cloud/bigquery_v2/types/table_reference.py +80 -0
  54. google_cloud_bigquery-3.31.0.dist-info/LICENSE +202 -0
  55. google_cloud_bigquery-3.31.0.dist-info/METADATA +203 -0
  56. google_cloud_bigquery-3.31.0.dist-info/RECORD +58 -0
  57. google_cloud_bigquery-3.31.0.dist-info/WHEEL +5 -0
  58. google_cloud_bigquery-3.31.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1076 @@
1
+ # Copyright 2015 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Define API Datasets."""
16
+
17
+ from __future__ import absolute_import
18
+
19
+ import copy
20
+
21
+ import typing
22
+
23
+ import google.cloud._helpers # type: ignore
24
+
25
+ from google.cloud.bigquery import _helpers
26
+ from google.cloud.bigquery.model import ModelReference
27
+ from google.cloud.bigquery.routine import Routine, RoutineReference
28
+ from google.cloud.bigquery.table import Table, TableReference
29
+ from google.cloud.bigquery.encryption_configuration import EncryptionConfiguration
30
+ from google.cloud.bigquery import external_config
31
+
32
+ from typing import Optional, List, Dict, Any, Union
33
+
34
+
35
+ def _get_table_reference(self, table_id: str) -> TableReference:
36
+ """Constructs a TableReference.
37
+
38
+ Args:
39
+ table_id (str): The ID of the table.
40
+
41
+ Returns:
42
+ google.cloud.bigquery.table.TableReference:
43
+ A table reference for a table in this dataset.
44
+ """
45
+ return TableReference(self, table_id)
46
+
47
+
48
+ def _get_model_reference(self, model_id):
49
+ """Constructs a ModelReference.
50
+
51
+ Args:
52
+ model_id (str): the ID of the model.
53
+
54
+ Returns:
55
+ google.cloud.bigquery.model.ModelReference:
56
+ A ModelReference for a model in this dataset.
57
+ """
58
+ return ModelReference.from_api_repr(
59
+ {"projectId": self.project, "datasetId": self.dataset_id, "modelId": model_id}
60
+ )
61
+
62
+
63
+ def _get_routine_reference(self, routine_id):
64
+ """Constructs a RoutineReference.
65
+
66
+ Args:
67
+ routine_id (str): the ID of the routine.
68
+
69
+ Returns:
70
+ google.cloud.bigquery.routine.RoutineReference:
71
+ A RoutineReference for a routine in this dataset.
72
+ """
73
+ return RoutineReference.from_api_repr(
74
+ {
75
+ "projectId": self.project,
76
+ "datasetId": self.dataset_id,
77
+ "routineId": routine_id,
78
+ }
79
+ )
80
+
81
+
82
+ class DatasetReference(object):
83
+ """DatasetReferences are pointers to datasets.
84
+
85
+ See
86
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets#datasetreference
87
+
88
+ Args:
89
+ project (str): The ID of the project
90
+ dataset_id (str): The ID of the dataset
91
+
92
+ Raises:
93
+ ValueError: If either argument is not of type ``str``.
94
+ """
95
+
96
+ def __init__(self, project: str, dataset_id: str):
97
+ if not isinstance(project, str):
98
+ raise ValueError("Pass a string for project")
99
+ if not isinstance(dataset_id, str):
100
+ raise ValueError("Pass a string for dataset_id")
101
+ self._project = project
102
+ self._dataset_id = dataset_id
103
+
104
+ @property
105
+ def project(self):
106
+ """str: Project ID of the dataset."""
107
+ return self._project
108
+
109
+ @property
110
+ def dataset_id(self):
111
+ """str: Dataset ID."""
112
+ return self._dataset_id
113
+
114
+ @property
115
+ def path(self):
116
+ """str: URL path for the dataset based on project and dataset ID."""
117
+ return "/projects/%s/datasets/%s" % (self.project, self.dataset_id)
118
+
119
+ table = _get_table_reference
120
+
121
+ model = _get_model_reference
122
+
123
+ routine = _get_routine_reference
124
+
125
+ @classmethod
126
+ def from_api_repr(cls, resource: dict) -> "DatasetReference":
127
+ """Factory: construct a dataset reference given its API representation
128
+
129
+ Args:
130
+ resource (Dict[str, str]):
131
+ Dataset reference resource representation returned from the API
132
+
133
+ Returns:
134
+ google.cloud.bigquery.dataset.DatasetReference:
135
+ Dataset reference parsed from ``resource``.
136
+ """
137
+ project = resource["projectId"]
138
+ dataset_id = resource["datasetId"]
139
+ return cls(project, dataset_id)
140
+
141
+ @classmethod
142
+ def from_string(
143
+ cls, dataset_id: str, default_project: Optional[str] = None
144
+ ) -> "DatasetReference":
145
+ """Construct a dataset reference from dataset ID string.
146
+
147
+ Args:
148
+ dataset_id (str):
149
+ A dataset ID in standard SQL format. If ``default_project``
150
+ is not specified, this must include both the project ID and
151
+ the dataset ID, separated by ``.``.
152
+ default_project (Optional[str]):
153
+ The project ID to use when ``dataset_id`` does not include a
154
+ project ID.
155
+
156
+ Returns:
157
+ DatasetReference:
158
+ Dataset reference parsed from ``dataset_id``.
159
+
160
+ Examples:
161
+ >>> DatasetReference.from_string('my-project-id.some_dataset')
162
+ DatasetReference('my-project-id', 'some_dataset')
163
+
164
+ Raises:
165
+ ValueError:
166
+ If ``dataset_id`` is not a fully-qualified dataset ID in
167
+ standard SQL format.
168
+ """
169
+ output_dataset_id = dataset_id
170
+ parts = _helpers._split_id(dataset_id)
171
+
172
+ if len(parts) == 1:
173
+ if default_project is not None:
174
+ output_project_id = default_project
175
+ else:
176
+ raise ValueError(
177
+ "When default_project is not set, dataset_id must be a "
178
+ "fully-qualified dataset ID in standard SQL format, "
179
+ 'e.g., "project.dataset_id" got {}'.format(dataset_id)
180
+ )
181
+ elif len(parts) == 2:
182
+ output_project_id, output_dataset_id = parts
183
+ else:
184
+ raise ValueError(
185
+ "Too many parts in dataset_id. Expected a fully-qualified "
186
+ "dataset ID in standard SQL format, "
187
+ 'e.g. "project.dataset_id", got {}'.format(dataset_id)
188
+ )
189
+
190
+ return cls(output_project_id, output_dataset_id)
191
+
192
+ def to_api_repr(self) -> dict:
193
+ """Construct the API resource representation of this dataset reference
194
+
195
+ Returns:
196
+ Dict[str, str]: dataset reference represented as an API resource
197
+ """
198
+ return {"projectId": self._project, "datasetId": self._dataset_id}
199
+
200
+ def _key(self):
201
+ """A tuple key that uniquely describes this field.
202
+
203
+ Used to compute this instance's hashcode and evaluate equality.
204
+
205
+ Returns:
206
+ Tuple[str]: The contents of this :class:`.DatasetReference`.
207
+ """
208
+ return (self._project, self._dataset_id)
209
+
210
+ def __eq__(self, other):
211
+ if not isinstance(other, DatasetReference):
212
+ return NotImplemented
213
+ return self._key() == other._key()
214
+
215
+ def __ne__(self, other):
216
+ return not self == other
217
+
218
+ def __hash__(self):
219
+ return hash(self._key())
220
+
221
+ def __str__(self):
222
+ return f"{self.project}.{self._dataset_id}"
223
+
224
+ def __repr__(self):
225
+ return "DatasetReference{}".format(self._key())
226
+
227
+
228
+ class AccessEntry(object):
229
+ """Represents grant of an access role to an entity.
230
+
231
+ An entry must have exactly one of the allowed
232
+ :class:`google.cloud.bigquery.enums.EntityTypes`. If anything but ``view``, ``routine``,
233
+ or ``dataset`` are set, a ``role`` is also required. ``role`` is omitted for ``view``,
234
+ ``routine``, ``dataset``, because they are always read-only.
235
+
236
+ See https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets.
237
+
238
+ Args:
239
+ role:
240
+ Role granted to the entity. The following string values are
241
+ supported: `'READER'`, `'WRITER'`, `'OWNER'`. It may also be
242
+ :data:`None` if the ``entity_type`` is ``view``, ``routine``, or ``dataset``.
243
+
244
+ entity_type:
245
+ Type of entity being granted the role. See
246
+ :class:`google.cloud.bigquery.enums.EntityTypes` for supported types.
247
+
248
+ entity_id:
249
+ If the ``entity_type`` is not 'view', 'routine', or 'dataset', the
250
+ ``entity_id`` is the ``str`` ID of the entity being granted the role. If
251
+ the ``entity_type`` is 'view' or 'routine', the ``entity_id`` is a ``dict``
252
+ representing the view or routine from a different dataset to grant access
253
+ to in the following format for views::
254
+
255
+ {
256
+ 'projectId': string,
257
+ 'datasetId': string,
258
+ 'tableId': string
259
+ }
260
+
261
+ For routines::
262
+
263
+ {
264
+ 'projectId': string,
265
+ 'datasetId': string,
266
+ 'routineId': string
267
+ }
268
+
269
+ If the ``entity_type`` is 'dataset', the ``entity_id`` is a ``dict`` that includes
270
+ a 'dataset' field with a ``dict`` representing the dataset and a 'target_types'
271
+ field with a ``str`` value of the dataset's resource type::
272
+
273
+ {
274
+ 'dataset': {
275
+ 'projectId': string,
276
+ 'datasetId': string,
277
+ },
278
+ 'target_types: 'VIEWS'
279
+ }
280
+
281
+ Raises:
282
+ ValueError:
283
+ If a ``view``, ``routine``, or ``dataset`` has ``role`` set, or a non ``view``,
284
+ non ``routine``, and non ``dataset`` **does not** have a ``role`` set.
285
+
286
+ Examples:
287
+ >>> entry = AccessEntry('OWNER', 'userByEmail', 'user@example.com')
288
+
289
+ >>> view = {
290
+ ... 'projectId': 'my-project',
291
+ ... 'datasetId': 'my_dataset',
292
+ ... 'tableId': 'my_table'
293
+ ... }
294
+ >>> entry = AccessEntry(None, 'view', view)
295
+ """
296
+
297
+ def __init__(
298
+ self,
299
+ role: Optional[str] = None,
300
+ entity_type: Optional[str] = None,
301
+ entity_id: Optional[Union[Dict[str, Any], str]] = None,
302
+ ):
303
+ self._properties = {}
304
+ if entity_type is not None:
305
+ self._properties[entity_type] = entity_id
306
+ self._properties["role"] = role
307
+ self._entity_type = entity_type
308
+
309
+ @property
310
+ def role(self) -> Optional[str]:
311
+ """The role of the entry."""
312
+ return typing.cast(Optional[str], self._properties.get("role"))
313
+
314
+ @role.setter
315
+ def role(self, value):
316
+ self._properties["role"] = value
317
+
318
+ @property
319
+ def dataset(self) -> Optional[DatasetReference]:
320
+ """API resource representation of a dataset reference."""
321
+ value = _helpers._get_sub_prop(self._properties, ["dataset", "dataset"])
322
+ return DatasetReference.from_api_repr(value) if value else None
323
+
324
+ @dataset.setter
325
+ def dataset(self, value):
326
+ if self.role is not None:
327
+ raise ValueError(
328
+ "Role must be None for a dataset. Current " "role: %r" % (self.role)
329
+ )
330
+
331
+ if isinstance(value, str):
332
+ value = DatasetReference.from_string(value).to_api_repr()
333
+
334
+ if isinstance(value, (Dataset, DatasetListItem)):
335
+ value = value.reference.to_api_repr()
336
+
337
+ _helpers._set_sub_prop(self._properties, ["dataset", "dataset"], value)
338
+ _helpers._set_sub_prop(
339
+ self._properties,
340
+ ["dataset", "targetTypes"],
341
+ self._properties.get("targetTypes"),
342
+ )
343
+
344
+ @property
345
+ def dataset_target_types(self) -> Optional[List[str]]:
346
+ """Which resources that the dataset in this entry applies to."""
347
+ return typing.cast(
348
+ Optional[List[str]],
349
+ _helpers._get_sub_prop(self._properties, ["dataset", "targetTypes"]),
350
+ )
351
+
352
+ @dataset_target_types.setter
353
+ def dataset_target_types(self, value):
354
+ self._properties.setdefault("dataset", {})
355
+ _helpers._set_sub_prop(self._properties, ["dataset", "targetTypes"], value)
356
+
357
+ @property
358
+ def routine(self) -> Optional[RoutineReference]:
359
+ """API resource representation of a routine reference."""
360
+ value = typing.cast(Optional[Dict], self._properties.get("routine"))
361
+ return RoutineReference.from_api_repr(value) if value else None
362
+
363
+ @routine.setter
364
+ def routine(self, value):
365
+ if self.role is not None:
366
+ raise ValueError(
367
+ "Role must be None for a routine. Current " "role: %r" % (self.role)
368
+ )
369
+
370
+ if isinstance(value, str):
371
+ value = RoutineReference.from_string(value).to_api_repr()
372
+
373
+ if isinstance(value, RoutineReference):
374
+ value = value.to_api_repr()
375
+
376
+ if isinstance(value, Routine):
377
+ value = value.reference.to_api_repr()
378
+
379
+ self._properties["routine"] = value
380
+
381
+ @property
382
+ def view(self) -> Optional[TableReference]:
383
+ """API resource representation of a view reference."""
384
+ value = typing.cast(Optional[Dict], self._properties.get("view"))
385
+ return TableReference.from_api_repr(value) if value else None
386
+
387
+ @view.setter
388
+ def view(self, value):
389
+ if self.role is not None:
390
+ raise ValueError(
391
+ "Role must be None for a view. Current " "role: %r" % (self.role)
392
+ )
393
+
394
+ if isinstance(value, str):
395
+ value = TableReference.from_string(value).to_api_repr()
396
+
397
+ if isinstance(value, TableReference):
398
+ value = value.to_api_repr()
399
+
400
+ if isinstance(value, Table):
401
+ value = value.reference.to_api_repr()
402
+
403
+ self._properties["view"] = value
404
+
405
+ @property
406
+ def group_by_email(self) -> Optional[str]:
407
+ """An email address of a Google Group to grant access to."""
408
+ return typing.cast(Optional[str], self._properties.get("groupByEmail"))
409
+
410
+ @group_by_email.setter
411
+ def group_by_email(self, value):
412
+ self._properties["groupByEmail"] = value
413
+
414
+ @property
415
+ def user_by_email(self) -> Optional[str]:
416
+ """An email address of a user to grant access to."""
417
+ return typing.cast(Optional[str], self._properties.get("userByEmail"))
418
+
419
+ @user_by_email.setter
420
+ def user_by_email(self, value):
421
+ self._properties["userByEmail"] = value
422
+
423
+ @property
424
+ def domain(self) -> Optional[str]:
425
+ """A domain to grant access to."""
426
+ return typing.cast(Optional[str], self._properties.get("domain"))
427
+
428
+ @domain.setter
429
+ def domain(self, value):
430
+ self._properties["domain"] = value
431
+
432
+ @property
433
+ def special_group(self) -> Optional[str]:
434
+ """A special group to grant access to."""
435
+ return typing.cast(Optional[str], self._properties.get("specialGroup"))
436
+
437
+ @special_group.setter
438
+ def special_group(self, value):
439
+ self._properties["specialGroup"] = value
440
+
441
+ @property
442
+ def entity_type(self) -> Optional[str]:
443
+ """The entity_type of the entry."""
444
+ return self._entity_type
445
+
446
+ @property
447
+ def entity_id(self) -> Optional[Union[Dict[str, Any], str]]:
448
+ """The entity_id of the entry."""
449
+ return self._properties.get(self._entity_type) if self._entity_type else None
450
+
451
+ def __eq__(self, other):
452
+ if not isinstance(other, AccessEntry):
453
+ return NotImplemented
454
+ return self._key() == other._key()
455
+
456
+ def __ne__(self, other):
457
+ return not self == other
458
+
459
+ def __repr__(self):
460
+ return f"<AccessEntry: role={self.role}, {self._entity_type}={self.entity_id}>"
461
+
462
+ def _key(self):
463
+ """A tuple key that uniquely describes this field.
464
+ Used to compute this instance's hashcode and evaluate equality.
465
+ Returns:
466
+ Tuple: The contents of this :class:`~google.cloud.bigquery.dataset.AccessEntry`.
467
+ """
468
+ properties = self._properties.copy()
469
+ prop_tup = tuple(sorted(properties.items()))
470
+ return (self.role, self._entity_type, self.entity_id, prop_tup)
471
+
472
+ def __hash__(self):
473
+ return hash(self._key())
474
+
475
+ def to_api_repr(self):
476
+ """Construct the API resource representation of this access entry
477
+
478
+ Returns:
479
+ Dict[str, object]: Access entry represented as an API resource
480
+ """
481
+ resource = copy.deepcopy(self._properties)
482
+ return resource
483
+
484
+ @classmethod
485
+ def from_api_repr(cls, resource: dict) -> "AccessEntry":
486
+ """Factory: construct an access entry given its API representation
487
+
488
+ Args:
489
+ resource (Dict[str, object]):
490
+ Access entry resource representation returned from the API
491
+
492
+ Returns:
493
+ google.cloud.bigquery.dataset.AccessEntry:
494
+ Access entry parsed from ``resource``.
495
+
496
+ Raises:
497
+ ValueError:
498
+ If the resource has more keys than ``role`` and one additional
499
+ key.
500
+ """
501
+ entry = resource.copy()
502
+ role = entry.pop("role", None)
503
+ entity_type, entity_id = entry.popitem()
504
+ if len(entry) != 0:
505
+ raise ValueError("Entry has unexpected keys remaining.", entry)
506
+
507
+ return cls(role, entity_type, entity_id)
508
+
509
+
510
+ class Dataset(object):
511
+ """Datasets are containers for tables.
512
+
513
+ See
514
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets#resource-dataset
515
+
516
+ Args:
517
+ dataset_ref (Union[google.cloud.bigquery.dataset.DatasetReference, str]):
518
+ A pointer to a dataset. If ``dataset_ref`` is a string, it must
519
+ include both the project ID and the dataset ID, separated by
520
+ ``.``.
521
+ """
522
+
523
+ _PROPERTY_TO_API_FIELD = {
524
+ "access_entries": "access",
525
+ "created": "creationTime",
526
+ "default_partition_expiration_ms": "defaultPartitionExpirationMs",
527
+ "default_table_expiration_ms": "defaultTableExpirationMs",
528
+ "friendly_name": "friendlyName",
529
+ "default_encryption_configuration": "defaultEncryptionConfiguration",
530
+ "is_case_insensitive": "isCaseInsensitive",
531
+ "storage_billing_model": "storageBillingModel",
532
+ "max_time_travel_hours": "maxTimeTravelHours",
533
+ "default_rounding_mode": "defaultRoundingMode",
534
+ "resource_tags": "resourceTags",
535
+ "external_catalog_dataset_options": "externalCatalogDatasetOptions",
536
+ }
537
+
538
+ def __init__(self, dataset_ref) -> None:
539
+ if isinstance(dataset_ref, str):
540
+ dataset_ref = DatasetReference.from_string(dataset_ref)
541
+ self._properties = {"datasetReference": dataset_ref.to_api_repr(), "labels": {}}
542
+
543
+ @property
544
+ def max_time_travel_hours(self):
545
+ """
546
+ Optional[int]: Defines the time travel window in hours. The value can
547
+ be from 48 to 168 hours (2 to 7 days), and in multiple of 24 hours
548
+ (48, 72, 96, 120, 144, 168).
549
+ The default value is 168 hours if this is not set.
550
+ """
551
+ return self._properties.get("maxTimeTravelHours")
552
+
553
+ @max_time_travel_hours.setter
554
+ def max_time_travel_hours(self, hours):
555
+ if not isinstance(hours, int):
556
+ raise ValueError(f"max_time_travel_hours must be an integer. Got {hours}")
557
+ if hours < 2 * 24 or hours > 7 * 24:
558
+ raise ValueError(
559
+ "Time Travel Window should be from 48 to 168 hours (2 to 7 days)"
560
+ )
561
+ if hours % 24 != 0:
562
+ raise ValueError("Time Travel Window should be multiple of 24")
563
+ self._properties["maxTimeTravelHours"] = hours
564
+
565
+ @property
566
+ def default_rounding_mode(self):
567
+ """Union[str, None]: defaultRoundingMode of the dataset as set by the user
568
+ (defaults to :data:`None`).
569
+
570
+ Set the value to one of ``'ROUND_HALF_AWAY_FROM_ZERO'``, ``'ROUND_HALF_EVEN'``, or
571
+ ``'ROUNDING_MODE_UNSPECIFIED'``.
572
+
573
+ See `default rounding mode
574
+ <https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets#Dataset.FIELDS.default_rounding_mode>`_
575
+ in REST API docs and `updating the default rounding model
576
+ <https://cloud.google.com/bigquery/docs/updating-datasets#update_rounding_mode>`_
577
+ guide.
578
+
579
+ Raises:
580
+ ValueError: for invalid value types.
581
+ """
582
+ return self._properties.get("defaultRoundingMode")
583
+
584
+ @default_rounding_mode.setter
585
+ def default_rounding_mode(self, value):
586
+ possible_values = [
587
+ "ROUNDING_MODE_UNSPECIFIED",
588
+ "ROUND_HALF_AWAY_FROM_ZERO",
589
+ "ROUND_HALF_EVEN",
590
+ ]
591
+ if not isinstance(value, str) and value is not None:
592
+ raise ValueError("Pass a string, or None")
593
+ if value is None:
594
+ self._properties["defaultRoundingMode"] = "ROUNDING_MODE_UNSPECIFIED"
595
+ if value not in possible_values and value is not None:
596
+ raise ValueError(
597
+ f'rounding mode needs to be one of {",".join(possible_values)}'
598
+ )
599
+ if value:
600
+ self._properties["defaultRoundingMode"] = value
601
+
602
+ @property
603
+ def project(self):
604
+ """str: Project ID of the project bound to the dataset."""
605
+ return self._properties["datasetReference"]["projectId"]
606
+
607
+ @property
608
+ def path(self):
609
+ """str: URL path for the dataset based on project and dataset ID."""
610
+ return "/projects/%s/datasets/%s" % (self.project, self.dataset_id)
611
+
612
+ @property
613
+ def access_entries(self):
614
+ """List[google.cloud.bigquery.dataset.AccessEntry]: Dataset's access
615
+ entries.
616
+
617
+ ``role`` augments the entity type and must be present **unless** the
618
+ entity type is ``view`` or ``routine``.
619
+
620
+ Raises:
621
+ TypeError: If 'value' is not a sequence
622
+ ValueError:
623
+ If any item in the sequence is not an
624
+ :class:`~google.cloud.bigquery.dataset.AccessEntry`.
625
+ """
626
+ entries = self._properties.get("access", [])
627
+ return [AccessEntry.from_api_repr(entry) for entry in entries]
628
+
629
+ @access_entries.setter
630
+ def access_entries(self, value):
631
+ if not all(isinstance(field, AccessEntry) for field in value):
632
+ raise ValueError("Values must be AccessEntry instances")
633
+ entries = [entry.to_api_repr() for entry in value]
634
+ self._properties["access"] = entries
635
+
636
+ @property
637
+ def created(self):
638
+ """Union[datetime.datetime, None]: Datetime at which the dataset was
639
+ created (:data:`None` until set from the server).
640
+ """
641
+ creation_time = self._properties.get("creationTime")
642
+ if creation_time is not None:
643
+ # creation_time will be in milliseconds.
644
+ return google.cloud._helpers._datetime_from_microseconds(
645
+ 1000.0 * float(creation_time)
646
+ )
647
+
648
+ @property
649
+ def dataset_id(self):
650
+ """str: Dataset ID."""
651
+ return self._properties["datasetReference"]["datasetId"]
652
+
653
+ @property
654
+ def full_dataset_id(self):
655
+ """Union[str, None]: ID for the dataset resource (:data:`None` until
656
+ set from the server)
657
+
658
+ In the format ``project_id:dataset_id``.
659
+ """
660
+ return self._properties.get("id")
661
+
662
+ @property
663
+ def reference(self):
664
+ """google.cloud.bigquery.dataset.DatasetReference: A reference to this
665
+ dataset.
666
+ """
667
+ return DatasetReference(self.project, self.dataset_id)
668
+
669
+ @property
670
+ def etag(self):
671
+ """Union[str, None]: ETag for the dataset resource (:data:`None` until
672
+ set from the server).
673
+ """
674
+ return self._properties.get("etag")
675
+
676
+ @property
677
+ def modified(self):
678
+ """Union[datetime.datetime, None]: Datetime at which the dataset was
679
+ last modified (:data:`None` until set from the server).
680
+ """
681
+ modified_time = self._properties.get("lastModifiedTime")
682
+ if modified_time is not None:
683
+ # modified_time will be in milliseconds.
684
+ return google.cloud._helpers._datetime_from_microseconds(
685
+ 1000.0 * float(modified_time)
686
+ )
687
+
688
+ @property
689
+ def self_link(self):
690
+ """Union[str, None]: URL for the dataset resource (:data:`None` until
691
+ set from the server).
692
+ """
693
+ return self._properties.get("selfLink")
694
+
695
+ @property
696
+ def default_partition_expiration_ms(self):
697
+ """Optional[int]: The default partition expiration for all
698
+ partitioned tables in the dataset, in milliseconds.
699
+
700
+ Once this property is set, all newly-created partitioned tables in
701
+ the dataset will have an ``time_paritioning.expiration_ms`` property
702
+ set to this value, and changing the value will only affect new
703
+ tables, not existing ones. The storage in a partition will have an
704
+ expiration time of its partition time plus this value.
705
+
706
+ Setting this property overrides the use of
707
+ ``default_table_expiration_ms`` for partitioned tables: only one of
708
+ ``default_table_expiration_ms`` and
709
+ ``default_partition_expiration_ms`` will be used for any new
710
+ partitioned table. If you provide an explicit
711
+ ``time_partitioning.expiration_ms`` when creating or updating a
712
+ partitioned table, that value takes precedence over the default
713
+ partition expiration time indicated by this property.
714
+ """
715
+ return _helpers._int_or_none(
716
+ self._properties.get("defaultPartitionExpirationMs")
717
+ )
718
+
719
+ @default_partition_expiration_ms.setter
720
+ def default_partition_expiration_ms(self, value):
721
+ self._properties["defaultPartitionExpirationMs"] = _helpers._str_or_none(value)
722
+
723
+ @property
724
+ def default_table_expiration_ms(self):
725
+ """Union[int, None]: Default expiration time for tables in the dataset
726
+ (defaults to :data:`None`).
727
+
728
+ Raises:
729
+ ValueError: For invalid value types.
730
+ """
731
+ return _helpers._int_or_none(self._properties.get("defaultTableExpirationMs"))
732
+
733
+ @default_table_expiration_ms.setter
734
+ def default_table_expiration_ms(self, value):
735
+ if not isinstance(value, int) and value is not None:
736
+ raise ValueError("Pass an integer, or None")
737
+ self._properties["defaultTableExpirationMs"] = _helpers._str_or_none(value)
738
+
739
+ @property
740
+ def description(self):
741
+ """Optional[str]: Description of the dataset as set by the user
742
+ (defaults to :data:`None`).
743
+
744
+ Raises:
745
+ ValueError: for invalid value types.
746
+ """
747
+ return self._properties.get("description")
748
+
749
+ @description.setter
750
+ def description(self, value):
751
+ if not isinstance(value, str) and value is not None:
752
+ raise ValueError("Pass a string, or None")
753
+ self._properties["description"] = value
754
+
755
+ @property
756
+ def friendly_name(self):
757
+ """Union[str, None]: Title of the dataset as set by the user
758
+ (defaults to :data:`None`).
759
+
760
+ Raises:
761
+ ValueError: for invalid value types.
762
+ """
763
+ return self._properties.get("friendlyName")
764
+
765
+ @friendly_name.setter
766
+ def friendly_name(self, value):
767
+ if not isinstance(value, str) and value is not None:
768
+ raise ValueError("Pass a string, or None")
769
+ self._properties["friendlyName"] = value
770
+
771
+ @property
772
+ def location(self):
773
+ """Union[str, None]: Location in which the dataset is hosted as set by
774
+ the user (defaults to :data:`None`).
775
+
776
+ Raises:
777
+ ValueError: for invalid value types.
778
+ """
779
+ return self._properties.get("location")
780
+
781
+ @location.setter
782
+ def location(self, value):
783
+ if not isinstance(value, str) and value is not None:
784
+ raise ValueError("Pass a string, or None")
785
+ self._properties["location"] = value
786
+
787
+ @property
788
+ def labels(self):
789
+ """Dict[str, str]: Labels for the dataset.
790
+
791
+ This method always returns a dict. To change a dataset's labels,
792
+ modify the dict, then call
793
+ :meth:`google.cloud.bigquery.client.Client.update_dataset`. To delete
794
+ a label, set its value to :data:`None` before updating.
795
+
796
+ Raises:
797
+ ValueError: for invalid value types.
798
+ """
799
+ return self._properties.setdefault("labels", {})
800
+
801
+ @labels.setter
802
+ def labels(self, value):
803
+ if not isinstance(value, dict):
804
+ raise ValueError("Pass a dict")
805
+ self._properties["labels"] = value
806
+
807
+ @property
808
+ def resource_tags(self):
809
+ """Dict[str, str]: Resource tags of the dataset.
810
+
811
+ Optional. The tags attached to this dataset. Tag keys are globally
812
+ unique. Tag key is expected to be in the namespaced format, for
813
+ example "123456789012/environment" where 123456789012 is
814
+ the ID of the parent organization or project resource for this tag
815
+ key. Tag value is expected to be the short name, for example
816
+ "Production".
817
+
818
+ Raises:
819
+ ValueError: for invalid value types.
820
+ """
821
+ return self._properties.setdefault("resourceTags", {})
822
+
823
+ @resource_tags.setter
824
+ def resource_tags(self, value):
825
+ if not isinstance(value, dict) and value is not None:
826
+ raise ValueError("Pass a dict")
827
+ self._properties["resourceTags"] = value
828
+
829
+ @property
830
+ def default_encryption_configuration(self):
831
+ """google.cloud.bigquery.encryption_configuration.EncryptionConfiguration: Custom
832
+ encryption configuration for all tables in the dataset.
833
+
834
+ Custom encryption configuration (e.g., Cloud KMS keys) or :data:`None`
835
+ if using default encryption.
836
+
837
+ See `protecting data with Cloud KMS keys
838
+ <https://cloud.google.com/bigquery/docs/customer-managed-encryption>`_
839
+ in the BigQuery documentation.
840
+ """
841
+ prop = self._properties.get("defaultEncryptionConfiguration")
842
+ if prop:
843
+ prop = EncryptionConfiguration.from_api_repr(prop)
844
+ return prop
845
+
846
+ @default_encryption_configuration.setter
847
+ def default_encryption_configuration(self, value):
848
+ api_repr = value
849
+ if value:
850
+ api_repr = value.to_api_repr()
851
+ self._properties["defaultEncryptionConfiguration"] = api_repr
852
+
853
+ @property
854
+ def is_case_insensitive(self):
855
+ """Optional[bool]: True if the dataset and its table names are case-insensitive, otherwise False.
856
+ By default, this is False, which means the dataset and its table names are case-sensitive.
857
+ This field does not affect routine references.
858
+
859
+ Raises:
860
+ ValueError: for invalid value types.
861
+ """
862
+ return self._properties.get("isCaseInsensitive") or False
863
+
864
+ @is_case_insensitive.setter
865
+ def is_case_insensitive(self, value):
866
+ if not isinstance(value, bool) and value is not None:
867
+ raise ValueError("Pass a boolean value, or None")
868
+ if value is None:
869
+ value = False
870
+ self._properties["isCaseInsensitive"] = value
871
+
872
+ @property
873
+ def storage_billing_model(self):
874
+ """Union[str, None]: StorageBillingModel of the dataset as set by the user
875
+ (defaults to :data:`None`).
876
+
877
+ Set the value to one of ``'LOGICAL'``, ``'PHYSICAL'``, or
878
+ ``'STORAGE_BILLING_MODEL_UNSPECIFIED'``. This change takes 24 hours to
879
+ take effect and you must wait 14 days before you can change the storage
880
+ billing model again.
881
+
882
+ See `storage billing model
883
+ <https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets#Dataset.FIELDS.storage_billing_model>`_
884
+ in REST API docs and `updating the storage billing model
885
+ <https://cloud.google.com/bigquery/docs/updating-datasets#update_storage_billing_models>`_
886
+ guide.
887
+
888
+ Raises:
889
+ ValueError: for invalid value types.
890
+ """
891
+ return self._properties.get("storageBillingModel")
892
+
893
+ @storage_billing_model.setter
894
+ def storage_billing_model(self, value):
895
+ if not isinstance(value, str) and value is not None:
896
+ raise ValueError(
897
+ "storage_billing_model must be a string (e.g. 'LOGICAL',"
898
+ " 'PHYSICAL', 'STORAGE_BILLING_MODEL_UNSPECIFIED'), or None."
899
+ f" Got {repr(value)}."
900
+ )
901
+ self._properties["storageBillingModel"] = value
902
+
903
+ @property
904
+ def external_catalog_dataset_options(self):
905
+ """Options defining open source compatible datasets living in the
906
+ BigQuery catalog. Contains metadata of open source database, schema
907
+ or namespace represented by the current dataset."""
908
+
909
+ prop = _helpers._get_sub_prop(
910
+ self._properties, ["externalCatalogDatasetOptions"]
911
+ )
912
+
913
+ if prop is not None:
914
+ prop = external_config.ExternalCatalogDatasetOptions.from_api_repr(prop)
915
+ return prop
916
+
917
+ @external_catalog_dataset_options.setter
918
+ def external_catalog_dataset_options(self, value):
919
+ value = _helpers._isinstance_or_raise(
920
+ value, external_config.ExternalCatalogDatasetOptions, none_allowed=True
921
+ )
922
+ self._properties[
923
+ self._PROPERTY_TO_API_FIELD["external_catalog_dataset_options"]
924
+ ] = (value.to_api_repr() if value is not None else None)
925
+
926
+ @classmethod
927
+ def from_string(cls, full_dataset_id: str) -> "Dataset":
928
+ """Construct a dataset from fully-qualified dataset ID.
929
+
930
+ Args:
931
+ full_dataset_id (str):
932
+ A fully-qualified dataset ID in standard SQL format. Must
933
+ include both the project ID and the dataset ID, separated by
934
+ ``.``.
935
+
936
+ Returns:
937
+ Dataset: Dataset parsed from ``full_dataset_id``.
938
+
939
+ Examples:
940
+ >>> Dataset.from_string('my-project-id.some_dataset')
941
+ Dataset(DatasetReference('my-project-id', 'some_dataset'))
942
+
943
+ Raises:
944
+ ValueError:
945
+ If ``full_dataset_id`` is not a fully-qualified dataset ID in
946
+ standard SQL format.
947
+ """
948
+ return cls(DatasetReference.from_string(full_dataset_id))
949
+
950
+ @classmethod
951
+ def from_api_repr(cls, resource: dict) -> "Dataset":
952
+ """Factory: construct a dataset given its API representation
953
+
954
+ Args:
955
+ resource (Dict[str: object]):
956
+ Dataset resource representation returned from the API
957
+
958
+ Returns:
959
+ google.cloud.bigquery.dataset.Dataset:
960
+ Dataset parsed from ``resource``.
961
+ """
962
+ if (
963
+ "datasetReference" not in resource
964
+ or "datasetId" not in resource["datasetReference"]
965
+ ):
966
+ raise KeyError(
967
+ "Resource lacks required identity information:"
968
+ '["datasetReference"]["datasetId"]'
969
+ )
970
+ project_id = resource["datasetReference"]["projectId"]
971
+ dataset_id = resource["datasetReference"]["datasetId"]
972
+ dataset = cls(DatasetReference(project_id, dataset_id))
973
+ dataset._properties = copy.deepcopy(resource)
974
+ return dataset
975
+
976
+ def to_api_repr(self) -> dict:
977
+ """Construct the API resource representation of this dataset
978
+
979
+ Returns:
980
+ Dict[str, object]: The dataset represented as an API resource
981
+ """
982
+ return copy.deepcopy(self._properties)
983
+
984
+ def _build_resource(self, filter_fields):
985
+ """Generate a resource for ``update``."""
986
+ return _helpers._build_resource_from_properties(self, filter_fields)
987
+
988
+ table = _get_table_reference
989
+
990
+ model = _get_model_reference
991
+
992
+ routine = _get_routine_reference
993
+
994
+ def __repr__(self):
995
+ return "Dataset({})".format(repr(self.reference))
996
+
997
+
998
+ class DatasetListItem(object):
999
+ """A read-only dataset resource from a list operation.
1000
+
1001
+ For performance reasons, the BigQuery API only includes some of the
1002
+ dataset properties when listing datasets. Notably,
1003
+ :attr:`~google.cloud.bigquery.dataset.Dataset.access_entries` is missing.
1004
+
1005
+ For a full list of the properties that the BigQuery API returns, see the
1006
+ `REST documentation for datasets.list
1007
+ <https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets/list>`_.
1008
+
1009
+
1010
+ Args:
1011
+ resource (Dict[str, str]):
1012
+ A dataset-like resource object from a dataset list response. A
1013
+ ``datasetReference`` property is required.
1014
+
1015
+ Raises:
1016
+ ValueError:
1017
+ If ``datasetReference`` or one of its required members is missing
1018
+ from ``resource``.
1019
+ """
1020
+
1021
+ def __init__(self, resource):
1022
+ if "datasetReference" not in resource:
1023
+ raise ValueError("resource must contain a datasetReference value")
1024
+ if "projectId" not in resource["datasetReference"]:
1025
+ raise ValueError(
1026
+ "resource['datasetReference'] must contain a projectId value"
1027
+ )
1028
+ if "datasetId" not in resource["datasetReference"]:
1029
+ raise ValueError(
1030
+ "resource['datasetReference'] must contain a datasetId value"
1031
+ )
1032
+ self._properties = resource
1033
+
1034
+ @property
1035
+ def project(self):
1036
+ """str: Project bound to the dataset."""
1037
+ return self._properties["datasetReference"]["projectId"]
1038
+
1039
+ @property
1040
+ def dataset_id(self):
1041
+ """str: Dataset ID."""
1042
+ return self._properties["datasetReference"]["datasetId"]
1043
+
1044
+ @property
1045
+ def full_dataset_id(self):
1046
+ """Union[str, None]: ID for the dataset resource (:data:`None` until
1047
+ set from the server)
1048
+
1049
+ In the format ``project_id:dataset_id``.
1050
+ """
1051
+ return self._properties.get("id")
1052
+
1053
+ @property
1054
+ def friendly_name(self):
1055
+ """Union[str, None]: Title of the dataset as set by the user
1056
+ (defaults to :data:`None`).
1057
+ """
1058
+ return self._properties.get("friendlyName")
1059
+
1060
+ @property
1061
+ def labels(self):
1062
+ """Dict[str, str]: Labels for the dataset."""
1063
+ return self._properties.setdefault("labels", {})
1064
+
1065
+ @property
1066
+ def reference(self):
1067
+ """google.cloud.bigquery.dataset.DatasetReference: A reference to this
1068
+ dataset.
1069
+ """
1070
+ return DatasetReference(self.project, self.dataset_id)
1071
+
1072
+ table = _get_table_reference
1073
+
1074
+ model = _get_model_reference
1075
+
1076
+ routine = _get_routine_reference