google-cloud-bigquery 3.22.0__tar.gz → 3.23.0__tar.gz

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 (153) hide show
  1. {google-cloud-bigquery-3.22.0/google_cloud_bigquery.egg-info → google-cloud-bigquery-3.23.0}/PKG-INFO +1 -1
  2. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/_helpers.py +50 -2
  3. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/_versions_helpers.py +14 -0
  4. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/table.py +15 -33
  5. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/version.py +1 -1
  6. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0/google_cloud_bigquery.egg-info}/PKG-INFO +1 -1
  7. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test__helpers.py +112 -2
  8. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/LICENSE +0 -0
  9. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/MANIFEST.in +0 -0
  10. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/README.rst +0 -0
  11. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/__init__.py +0 -0
  12. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/_http.py +0 -0
  13. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/_job_helpers.py +0 -0
  14. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/_pandas_helpers.py +0 -0
  15. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/_pyarrow_helpers.py +0 -0
  16. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/_tqdm_helpers.py +0 -0
  17. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/client.py +0 -0
  18. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/dataset.py +0 -0
  19. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/dbapi/__init__.py +0 -0
  20. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/dbapi/_helpers.py +0 -0
  21. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/dbapi/connection.py +0 -0
  22. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/dbapi/cursor.py +0 -0
  23. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/dbapi/exceptions.py +0 -0
  24. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/dbapi/types.py +0 -0
  25. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/encryption_configuration.py +0 -0
  26. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/enums.py +0 -0
  27. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/exceptions.py +0 -0
  28. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/external_config.py +0 -0
  29. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/format_options.py +0 -0
  30. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/iam.py +0 -0
  31. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/job/__init__.py +0 -0
  32. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/job/base.py +0 -0
  33. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/job/copy_.py +0 -0
  34. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/job/extract.py +0 -0
  35. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/job/load.py +0 -0
  36. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/job/query.py +0 -0
  37. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/magics/__init__.py +0 -0
  38. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/magics/line_arg_parser/__init__.py +0 -0
  39. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/magics/line_arg_parser/exceptions.py +0 -0
  40. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/magics/line_arg_parser/lexer.py +0 -0
  41. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/magics/line_arg_parser/parser.py +0 -0
  42. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/magics/line_arg_parser/visitors.py +0 -0
  43. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/magics/magics.py +0 -0
  44. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/model.py +0 -0
  45. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/opentelemetry_tracing.py +0 -0
  46. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/py.typed +0 -0
  47. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/query.py +0 -0
  48. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/retry.py +0 -0
  49. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/routine/__init__.py +0 -0
  50. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/routine/routine.py +0 -0
  51. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/schema.py +0 -0
  52. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery/standard_sql.py +0 -0
  53. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery_v2/__init__.py +0 -0
  54. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery_v2/types/__init__.py +0 -0
  55. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery_v2/types/encryption_config.py +0 -0
  56. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery_v2/types/model.py +0 -0
  57. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery_v2/types/model_reference.py +0 -0
  58. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery_v2/types/standard_sql.py +0 -0
  59. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google/cloud/bigquery_v2/types/table_reference.py +0 -0
  60. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google_cloud_bigquery.egg-info/SOURCES.txt +0 -0
  61. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google_cloud_bigquery.egg-info/dependency_links.txt +0 -0
  62. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google_cloud_bigquery.egg-info/not-zip-safe +0 -0
  63. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google_cloud_bigquery.egg-info/requires.txt +0 -0
  64. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/google_cloud_bigquery.egg-info/top_level.txt +0 -0
  65. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/setup.cfg +0 -0
  66. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/setup.py +0 -0
  67. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/__init__.py +0 -0
  68. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/characters.json +0 -0
  69. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/characters.jsonl +0 -0
  70. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/colors.avro +0 -0
  71. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/numeric_38_12.parquet +0 -0
  72. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/people.csv +0 -0
  73. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/scalars.csv +0 -0
  74. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/scalars.jsonl +0 -0
  75. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/scalars_extreme.jsonl +0 -0
  76. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/scalars_schema.json +0 -0
  77. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/scalars_schema_csv.json +0 -0
  78. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/data/schema.json +0 -0
  79. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/scrub_datasets.py +0 -0
  80. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/__init__.py +0 -0
  81. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/conftest.py +0 -0
  82. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/helpers.py +0 -0
  83. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_arrow.py +0 -0
  84. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_client.py +0 -0
  85. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_job_retry.py +0 -0
  86. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_list_rows.py +0 -0
  87. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_magics.py +0 -0
  88. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_pandas.py +0 -0
  89. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_query.py +0 -0
  90. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/system/test_structs.py +0 -0
  91. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/__init__.py +0 -0
  92. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/_helpers/__init__.py +0 -0
  93. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/_helpers/test_from_json.py +0 -0
  94. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/conftest.py +0 -0
  95. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/helpers.py +0 -0
  96. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/__init__.py +0 -0
  97. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/helpers.py +0 -0
  98. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_base.py +0 -0
  99. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_copy.py +0 -0
  100. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_extract.py +0 -0
  101. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_load.py +0 -0
  102. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_load_config.py +0 -0
  103. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_query.py +0 -0
  104. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_query_config.py +0 -0
  105. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_query_pandas.py +0 -0
  106. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/job/test_query_stats.py +0 -0
  107. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/line_arg_parser/__init__.py +0 -0
  108. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/line_arg_parser/test_lexer.py +0 -0
  109. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/line_arg_parser/test_parser.py +0 -0
  110. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/line_arg_parser/test_visitors.py +0 -0
  111. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/model/__init__.py +0 -0
  112. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/model/test_model.py +0 -0
  113. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/model/test_model_reference.py +0 -0
  114. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/routine/__init__.py +0 -0
  115. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/routine/test_remote_function_options.py +0 -0
  116. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/routine/test_routine.py +0 -0
  117. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/routine/test_routine_argument.py +0 -0
  118. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/routine/test_routine_reference.py +0 -0
  119. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test__http.py +0 -0
  120. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test__job_helpers.py +0 -0
  121. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test__pandas_helpers.py +0 -0
  122. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test__pyarrow_helpers.py +0 -0
  123. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test__versions_helpers.py +0 -0
  124. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_client.py +0 -0
  125. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_create_dataset.py +0 -0
  126. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_dataset.py +0 -0
  127. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_dbapi__helpers.py +0 -0
  128. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_dbapi_connection.py +0 -0
  129. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_dbapi_cursor.py +0 -0
  130. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_dbapi_types.py +0 -0
  131. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_delete_dataset.py +0 -0
  132. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_encryption_configuration.py +0 -0
  133. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_external_config.py +0 -0
  134. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_format_options.py +0 -0
  135. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_job_retry.py +0 -0
  136. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_legacy_types.py +0 -0
  137. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_list_datasets.py +0 -0
  138. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_list_jobs.py +0 -0
  139. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_list_models.py +0 -0
  140. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_list_projects.py +0 -0
  141. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_list_routines.py +0 -0
  142. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_list_tables.py +0 -0
  143. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_magics.py +0 -0
  144. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_opentelemetry_tracing.py +0 -0
  145. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_packaging.py +0 -0
  146. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_query.py +0 -0
  147. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_retry.py +0 -0
  148. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_schema.py +0 -0
  149. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_signature_compatibility.py +0 -0
  150. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_standard_sql_types.py +0 -0
  151. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_table.py +0 -0
  152. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_table_arrow.py +0 -0
  153. {google-cloud-bigquery-3.22.0 → google-cloud-bigquery-3.23.0}/tests/unit/test_table_pandas.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: google-cloud-bigquery
3
- Version: 3.22.0
3
+ Version: 3.23.0
4
4
  Summary: Google BigQuery API client library
5
5
  Home-page: https://github.com/googleapis/python-bigquery
6
6
  Author: Google LLC
@@ -50,6 +50,7 @@ _INTERVAL_PATTERN = re.compile(
50
50
  r"(?P<days>-?\d+) "
51
51
  r"(?P<time_sign>-?)(?P<hours>\d+):(?P<minutes>\d+):(?P<seconds>\d+)\.?(?P<fraction>\d*)?$"
52
52
  )
53
+ _RANGE_PATTERN = re.compile(r"\[.*, .*\)")
53
54
 
54
55
  BIGQUERY_EMULATOR_HOST = "BIGQUERY_EMULATOR_HOST"
55
56
  """Environment variable defining host for emulator."""
@@ -334,9 +335,8 @@ def _range_from_json(value, field):
334
335
  The parsed range object from ``value`` if the ``field`` is not
335
336
  null (otherwise it is :data:`None`).
336
337
  """
337
- range_literal = re.compile(r"\[.*, .*\)")
338
338
  if _not_null(value, field):
339
- if range_literal.match(value):
339
+ if _RANGE_PATTERN.match(value):
340
340
  start, end = value[1:-1].split(", ")
341
341
  start = _range_element_from_json(start, field.range_element_type)
342
342
  end = _range_element_from_json(end, field.range_element_type)
@@ -531,6 +531,52 @@ def _time_to_json(value):
531
531
  return value
532
532
 
533
533
 
534
+ def _range_element_to_json(value, element_type=None):
535
+ """Coerce 'value' to an JSON-compatible representation."""
536
+ if value is None:
537
+ return None
538
+ elif isinstance(value, str):
539
+ if value.upper() in ("UNBOUNDED", "NULL"):
540
+ return None
541
+ else:
542
+ # We do not enforce range element value to be valid to reduce
543
+ # redundancy with backend.
544
+ return value
545
+ elif (
546
+ element_type and element_type.element_type.upper() in _SUPPORTED_RANGE_ELEMENTS
547
+ ):
548
+ converter = _SCALAR_VALUE_TO_JSON_ROW.get(element_type.element_type.upper())
549
+ return converter(value)
550
+ else:
551
+ raise ValueError(
552
+ f"Unsupported RANGE element type {element_type}, or "
553
+ "element type is empty. Must be DATE, DATETIME, or "
554
+ "TIMESTAMP"
555
+ )
556
+
557
+
558
+ def _range_field_to_json(range_element_type, value):
559
+ """Coerce 'value' to an JSON-compatible representation."""
560
+ if isinstance(value, str):
561
+ # string literal
562
+ if _RANGE_PATTERN.match(value):
563
+ start, end = value[1:-1].split(", ")
564
+ else:
565
+ raise ValueError(f"RANGE literal {value} has incorrect format")
566
+ elif isinstance(value, dict):
567
+ # dictionary
568
+ start = value.get("start")
569
+ end = value.get("end")
570
+ else:
571
+ raise ValueError(
572
+ f"Unsupported type of RANGE value {value}, must be " "string or dict"
573
+ )
574
+
575
+ start = _range_element_to_json(start, range_element_type)
576
+ end = _range_element_to_json(end, range_element_type)
577
+ return {"start": start, "end": end}
578
+
579
+
534
580
  # Converters used for scalar values marshalled to the BigQuery API, such as in
535
581
  # query parameters or the tabledata.insert API.
536
582
  _SCALAR_VALUE_TO_JSON_ROW = {
@@ -676,6 +722,8 @@ def _single_field_to_json(field, row_value):
676
722
 
677
723
  if field.field_type == "RECORD":
678
724
  return _record_field_to_json(field.fields, row_value)
725
+ if field.field_type == "RANGE":
726
+ return _range_field_to_json(field.range_element_type, row_value)
679
727
 
680
728
  return _scalar_field_to_json(field, row_value)
681
729
 
@@ -26,6 +26,9 @@ _MIN_BQ_STORAGE_VERSION = packaging.version.Version("2.0.0")
26
26
  _BQ_STORAGE_OPTIONAL_READ_SESSION_VERSION = packaging.version.Version("2.6.0")
27
27
  _MIN_PANDAS_VERSION = packaging.version.Version("1.1.0")
28
28
 
29
+ _MIN_PANDAS_VERSION_RANGE = packaging.version.Version("1.5.0")
30
+ _MIN_PYARROW_VERSION_RANGE = packaging.version.Version("10.0.1")
31
+
29
32
 
30
33
  class PyarrowVersions:
31
34
  """Version comparisons for pyarrow package."""
@@ -234,3 +237,14 @@ class PandasVersions:
234
237
 
235
238
 
236
239
  PANDAS_VERSIONS = PandasVersions()
240
+
241
+ # Since RANGE support in pandas requires specific versions
242
+ # of both pyarrow and pandas, we make this a separate
243
+ # constant instead of as a property of PANDAS_VERSIONS
244
+ # or PYARROW_VERSIONS.
245
+ SUPPORTS_RANGE_PYARROW = (
246
+ PANDAS_VERSIONS.try_import() is not None
247
+ and PANDAS_VERSIONS.installed_version >= _MIN_PANDAS_VERSION_RANGE
248
+ and PYARROW_VERSIONS.try_import() is not None
249
+ and PYARROW_VERSIONS.installed_version >= _MIN_PYARROW_VERSION_RANGE
250
+ )
@@ -100,6 +100,12 @@ _NO_SUPPORTED_DTYPE = (
100
100
  "because the necessary `__from_arrow__` attribute is missing."
101
101
  )
102
102
 
103
+ _RANGE_PYARROW_WARNING = (
104
+ "Unable to represent RANGE schema as struct using pandas ArrowDtype. Using "
105
+ "`object` instead. To use ArrowDtype, use pandas >= 1.5 and "
106
+ "pyarrow >= 10.0.1."
107
+ )
108
+
103
109
  # How many of the total rows need to be downloaded already for us to skip
104
110
  # calling the BQ Storage API?
105
111
  ALMOST_COMPLETELY_CACHED_RATIO = 0.333
@@ -2279,26 +2285,18 @@ class RowIterator(HTTPIterator):
2279
2285
  time_dtype = db_dtypes.TimeDtype()
2280
2286
 
2281
2287
  if range_date_dtype is DefaultPandasDTypes.RANGE_DATE_DTYPE:
2282
- try:
2288
+ if _versions_helpers.SUPPORTS_RANGE_PYARROW:
2283
2289
  range_date_dtype = pandas.ArrowDtype(
2284
2290
  pyarrow.struct(
2285
2291
  [("start", pyarrow.date32()), ("end", pyarrow.date32())]
2286
2292
  )
2287
2293
  )
2288
- except AttributeError:
2289
- # pandas.ArrowDtype was introduced in pandas 1.5, but python 3.7
2290
- # only supports upto pandas 1.3. If pandas.ArrowDtype is not
2291
- # present, we raise a warning and set range_date_dtype to None.
2292
- msg = (
2293
- "Unable to find class ArrowDtype in pandas, setting "
2294
- "range_date_dtype to be None. To use ArrowDtype, please "
2295
- "use pandas >= 1.5 and python >= 3.8."
2296
- )
2297
- warnings.warn(msg)
2294
+ else:
2295
+ warnings.warn(_RANGE_PYARROW_WARNING)
2298
2296
  range_date_dtype = None
2299
2297
 
2300
2298
  if range_datetime_dtype is DefaultPandasDTypes.RANGE_DATETIME_DTYPE:
2301
- try:
2299
+ if _versions_helpers.SUPPORTS_RANGE_PYARROW:
2302
2300
  range_datetime_dtype = pandas.ArrowDtype(
2303
2301
  pyarrow.struct(
2304
2302
  [
@@ -2307,20 +2305,12 @@ class RowIterator(HTTPIterator):
2307
2305
  ]
2308
2306
  )
2309
2307
  )
2310
- except AttributeError:
2311
- # pandas.ArrowDtype was introduced in pandas 1.5, but python 3.7
2312
- # only supports upto pandas 1.3. If pandas.ArrowDtype is not
2313
- # present, we raise a warning and set range_datetime_dtype to None.
2314
- msg = (
2315
- "Unable to find class ArrowDtype in pandas, setting "
2316
- "range_datetime_dtype to be None. To use ArrowDtype, "
2317
- "please use pandas >= 1.5 and python >= 3.8."
2318
- )
2319
- warnings.warn(msg)
2308
+ else:
2309
+ warnings.warn(_RANGE_PYARROW_WARNING)
2320
2310
  range_datetime_dtype = None
2321
2311
 
2322
2312
  if range_timestamp_dtype is DefaultPandasDTypes.RANGE_TIMESTAMP_DTYPE:
2323
- try:
2313
+ if _versions_helpers.SUPPORTS_RANGE_PYARROW:
2324
2314
  range_timestamp_dtype = pandas.ArrowDtype(
2325
2315
  pyarrow.struct(
2326
2316
  [
@@ -2329,16 +2319,8 @@ class RowIterator(HTTPIterator):
2329
2319
  ]
2330
2320
  )
2331
2321
  )
2332
- except AttributeError:
2333
- # pandas.ArrowDtype was introduced in pandas 1.5, but python 3.7
2334
- # only supports upto pandas 1.3. If pandas.ArrowDtype is not
2335
- # present, we raise a warning and set range_timestamp_dtype to None.
2336
- msg = (
2337
- "Unable to find class ArrowDtype in pandas, setting "
2338
- "range_timestamp_dtype to be None. To use ArrowDtype, "
2339
- "please use pandas >= 1.5 and python >= 3.8."
2340
- )
2341
- warnings.warn(msg)
2322
+ else:
2323
+ warnings.warn(_RANGE_PYARROW_WARNING)
2342
2324
  range_timestamp_dtype = None
2343
2325
 
2344
2326
  if bool_dtype is not None and not hasattr(bool_dtype, "__from_arrow__"):
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "3.22.0"
15
+ __version__ = "3.23.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: google-cloud-bigquery
3
- Version: 3.22.0
3
+ Version: 3.23.0
4
4
  Summary: Google BigQuery API client library
5
5
  Home-page: https://github.com/googleapis/python-bigquery
6
6
  Author: Google LLC
@@ -1049,10 +1049,22 @@ class Test_time_to_json(unittest.TestCase):
1049
1049
  self.assertEqual(self._call_fut(when), "12:13:41")
1050
1050
 
1051
1051
 
1052
- def _make_field(field_type, mode="NULLABLE", name="testing", fields=()):
1052
+ def _make_field(
1053
+ field_type,
1054
+ mode="NULLABLE",
1055
+ name="testing",
1056
+ fields=(),
1057
+ range_element_type=None,
1058
+ ):
1053
1059
  from google.cloud.bigquery.schema import SchemaField
1054
1060
 
1055
- return SchemaField(name=name, field_type=field_type, mode=mode, fields=fields)
1061
+ return SchemaField(
1062
+ name=name,
1063
+ field_type=field_type,
1064
+ mode=mode,
1065
+ fields=fields,
1066
+ range_element_type=range_element_type,
1067
+ )
1056
1068
 
1057
1069
 
1058
1070
  class Test_scalar_field_to_json(unittest.TestCase):
@@ -1251,6 +1263,98 @@ class Test_record_field_to_json(unittest.TestCase):
1251
1263
  )
1252
1264
 
1253
1265
 
1266
+ class Test_range_field_to_json(unittest.TestCase):
1267
+ def _call_fut(self, field, value):
1268
+ from google.cloud.bigquery._helpers import _range_field_to_json
1269
+
1270
+ return _range_field_to_json(field, value)
1271
+
1272
+ def test_w_date(self):
1273
+ field = _make_field("RANGE", range_element_type="DATE")
1274
+ start = datetime.date(2016, 12, 3)
1275
+ original = {"start": start}
1276
+ converted = self._call_fut(field.range_element_type, original)
1277
+ expected = {"start": "2016-12-03", "end": None}
1278
+ self.assertEqual(converted, expected)
1279
+
1280
+ def test_w_date_string(self):
1281
+ field = _make_field("RANGE", range_element_type="DATE")
1282
+ original = {"start": "2016-12-03"}
1283
+ converted = self._call_fut(field.range_element_type, original)
1284
+ expected = {"start": "2016-12-03", "end": None}
1285
+ self.assertEqual(converted, expected)
1286
+
1287
+ def test_w_datetime(self):
1288
+ field = _make_field("RANGE", range_element_type="DATETIME")
1289
+ start = datetime.datetime(2016, 12, 3, 14, 11, 27, 123456)
1290
+ original = {"start": start}
1291
+ converted = self._call_fut(field.range_element_type, original)
1292
+ expected = {"start": "2016-12-03T14:11:27.123456", "end": None}
1293
+ self.assertEqual(converted, expected)
1294
+
1295
+ def test_w_datetime_string(self):
1296
+ field = _make_field("RANGE", range_element_type="DATETIME")
1297
+ original = {"start": "2016-12-03T14:11:27.123456"}
1298
+ converted = self._call_fut(field.range_element_type, original)
1299
+ expected = {"start": "2016-12-03T14:11:27.123456", "end": None}
1300
+ self.assertEqual(converted, expected)
1301
+
1302
+ def test_w_timestamp(self):
1303
+ from google.cloud._helpers import UTC
1304
+
1305
+ field = _make_field("RANGE", range_element_type="TIMESTAMP")
1306
+ start = datetime.datetime(2016, 12, 3, 14, 11, 27, 123456, tzinfo=UTC)
1307
+ original = {"start": start}
1308
+ converted = self._call_fut(field.range_element_type, original)
1309
+ expected = {"start": "2016-12-03T14:11:27.123456Z", "end": None}
1310
+ self.assertEqual(converted, expected)
1311
+
1312
+ def test_w_timestamp_string(self):
1313
+ field = _make_field("RANGE", range_element_type="TIMESTAMP")
1314
+ original = {"start": "2016-12-03T14:11:27.123456Z"}
1315
+ converted = self._call_fut(field.range_element_type, original)
1316
+ expected = {"start": "2016-12-03T14:11:27.123456Z", "end": None}
1317
+ self.assertEqual(converted, expected)
1318
+
1319
+ def test_w_timestamp_float(self):
1320
+ field = _make_field("RANGE", range_element_type="TIMESTAMP")
1321
+ original = {"start": 12.34567}
1322
+ converted = self._call_fut(field.range_element_type, original)
1323
+ expected = {"start": 12.34567, "end": None}
1324
+ self.assertEqual(converted, expected)
1325
+
1326
+ def test_w_string_literal(self):
1327
+ field = _make_field("RANGE", range_element_type="DATE")
1328
+ original = "[2016-12-03, UNBOUNDED)"
1329
+ converted = self._call_fut(field.range_element_type, original)
1330
+ expected = {"start": "2016-12-03", "end": None}
1331
+ self.assertEqual(converted, expected)
1332
+
1333
+ def test_w_unsupported_range_element_type(self):
1334
+ field = _make_field("RANGE", range_element_type="TIME")
1335
+ with self.assertRaises(ValueError):
1336
+ self._call_fut(
1337
+ field.range_element_type,
1338
+ {"start": datetime.time(12, 13, 41)},
1339
+ )
1340
+
1341
+ def test_w_no_range_element_type(self):
1342
+ field = _make_field("RANGE")
1343
+ with self.assertRaises(ValueError):
1344
+ self._call_fut(field.range_element_type, "2016-12-03")
1345
+
1346
+ def test_w_incorrect_literal_format(self):
1347
+ field = _make_field("RANGE", range_element_type="DATE")
1348
+ original = "[2016-12-03, UNBOUNDED]"
1349
+ with self.assertRaises(ValueError):
1350
+ self._call_fut(field.range_element_type, original)
1351
+
1352
+ def test_w_unsupported_representation(self):
1353
+ field = _make_field("RANGE", range_element_type="DATE")
1354
+ with self.assertRaises(ValueError):
1355
+ self._call_fut(field.range_element_type, object())
1356
+
1357
+
1254
1358
  class Test_field_to_json(unittest.TestCase):
1255
1359
  def _call_fut(self, field, value):
1256
1360
  from google.cloud.bigquery._helpers import _field_to_json
@@ -1285,6 +1389,12 @@ class Test_field_to_json(unittest.TestCase):
1285
1389
  converted = self._call_fut(field, original)
1286
1390
  self.assertEqual(converted, str(original))
1287
1391
 
1392
+ def test_w_range(self):
1393
+ field = _make_field("RANGE", range_element_type="DATE")
1394
+ original = {"start": "2016-12-03", "end": "2024-12-03"}
1395
+ converted = self._call_fut(field, original)
1396
+ self.assertEqual(converted, original)
1397
+
1288
1398
 
1289
1399
  class Test_snake_to_camel_case(unittest.TestCase):
1290
1400
  def _call_fut(self, value):