Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit428c023

Browse files
authored
Merge branch 'main' into support-jsonextension
2 parents5c99611 +575f7fc commit428c023

File tree

9 files changed

+198
-14
lines changed

9 files changed

+198
-14
lines changed

‎CHANGELOG.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,27 @@
55
[1]:https://pypi.org/project/google-cloud-bigquery/#history
66

77

8+
##[3.15.0](https://github.com/googleapis/python-bigquery/compare/v3.14.1...v3.15.0) (2024-01-09)
9+
10+
11+
###Features
12+
13+
* Support JSON type in`insert_rows` and as a scalar query parameter ([#1757](https://github.com/googleapis/python-bigquery/issues/1757)) ([02a7d12](https://github.com/googleapis/python-bigquery/commit/02a7d129776b7da7da844ffa9c5cdf21811cd3af))
14+
* Support RANGE in schema ([#1746](https://github.com/googleapis/python-bigquery/issues/1746)) ([8585747](https://github.com/googleapis/python-bigquery/commit/8585747058e6db49a8078ae44d8e10735cdc27f9))
15+
16+
17+
###Bug Fixes
18+
19+
* Deserializing JSON subfields within structs fails ([#1742](https://github.com/googleapis/python-bigquery/issues/1742)) ([0d93073](https://github.com/googleapis/python-bigquery/commit/0d930739c78b557db6cd48b38fe16eba93719c40))
20+
* Due to upstream change in dataset, updates expected results ([#1761](https://github.com/googleapis/python-bigquery/issues/1761)) ([132c14b](https://github.com/googleapis/python-bigquery/commit/132c14bbddfb61ea8bc408bef5e958e21b5b819c))
21+
* Load_table_from_dataframe for higher scale decimal ([#1703](https://github.com/googleapis/python-bigquery/issues/1703)) ([b9c8be0](https://github.com/googleapis/python-bigquery/commit/b9c8be0982c76187444300c414e0dda8b0ad105b))
22+
* Updates types-protobuf version for mypy-samples nox session ([#1764](https://github.com/googleapis/python-bigquery/issues/1764)) ([c0de695](https://github.com/googleapis/python-bigquery/commit/c0de6958e5761ad6ff532dd933b0f4387e18f1b9))
23+
24+
25+
###Performance Improvements
26+
27+
* DB-API uses more efficient`query_and_wait` when no job ID is provided ([#1747](https://github.com/googleapis/python-bigquery/issues/1747)) ([d225a94](https://github.com/googleapis/python-bigquery/commit/d225a94e718a85877c495fbd32eca607b8919ac6))
28+
829
##[3.14.1](https://github.com/googleapis/python-bigquery/compare/v3.14.0...v3.14.1) (2023-12-13)
930

1031

‎README.rst‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ the BigQuery client the following PyPI packages need to be installed:
117117

118118
..code-block::console
119119
120-
pip install google-cloud-bigquery[opentelemetry] opentelemetry-exporter-google-cloud
120+
pip install google-cloud-bigquery[opentelemetry] opentelemetry-exporter-gcp-trace
121121
122122
After installation, OpenTelemetry can be used in the BigQuery
123123
client and in BigQuery jobs. First, however, an exporter must be
@@ -128,12 +128,11 @@ example of this can be found here:
128128
129129
from opentelemetryimport trace
130130
from opentelemetry.sdk.traceimport TracerProvider
131-
from opentelemetry.sdk.trace.exportimportBatchExportSpanProcessor
131+
from opentelemetry.sdk.trace.exportimportBatchSpanProcessor
132132
from opentelemetry.exporter.cloud_traceimport CloudTraceSpanExporter
133+
tracer_provider= TracerProvider()
134+
tracer_provider= BatchSpanProcessor(CloudTraceSpanExporter())
133135
trace.set_tracer_provider(TracerProvider())
134-
trace.get_tracer_provider().add_span_processor(
135-
BatchExportSpanProcessor(CloudTraceSpanExporter())
136-
)
137136
138137
In this example all tracing data will be published to the Google
139138
`Cloud Trace`_ console. For more information on OpenTelemetry, please consult the `OpenTelemetry documentation`_.

‎google/cloud/bigquery/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
fromgoogle.cloud.bigquery.routineimportRemoteFunctionOptions
9797
fromgoogle.cloud.bigquery.schemaimportPolicyTagList
9898
fromgoogle.cloud.bigquery.schemaimportSchemaField
99+
fromgoogle.cloud.bigquery.schemaimportFieldElementType
99100
fromgoogle.cloud.bigquery.standard_sqlimportStandardSqlDataType
100101
fromgoogle.cloud.bigquery.standard_sqlimportStandardSqlField
101102
fromgoogle.cloud.bigquery.standard_sqlimportStandardSqlStructType
@@ -158,6 +159,7 @@
158159
"RemoteFunctionOptions",
159160
# Shared helpers
160161
"SchemaField",
162+
"FieldElementType",
161163
"PolicyTagList",
162164
"UDFResource",
163165
"ExternalConfig",

‎google/cloud/bigquery/schema.py‎

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
importcollections
1818
importenum
19-
fromtypingimportAny,Dict,Iterable,Optional,Union
19+
fromtypingimportAny,Dict,Iterable,Optional,Union,cast
2020

2121
fromgoogle.cloud.bigqueryimportstandard_sql
2222
fromgoogle.cloud.bigquery.enumsimportStandardSqlTypeNames
@@ -66,6 +66,46 @@ class _DefaultSentinel(enum.Enum):
6666
_DEFAULT_VALUE=_DefaultSentinel.DEFAULT_VALUE
6767

6868

69+
classFieldElementType(object):
70+
"""Represents the type of a field element.
71+
72+
Args:
73+
element_type (str): The type of a field element.
74+
"""
75+
76+
def__init__(self,element_type:str):
77+
self._properties= {}
78+
self._properties["type"]=element_type.upper()
79+
80+
@property
81+
defelement_type(self):
82+
returnself._properties.get("type")
83+
84+
@classmethod
85+
deffrom_api_repr(cls,api_repr:Optional[dict])->Optional["FieldElementType"]:
86+
"""Factory: construct a FieldElementType given its API representation.
87+
88+
Args:
89+
api_repr (Dict[str, str]): field element type as returned from
90+
the API.
91+
92+
Returns:
93+
google.cloud.bigquery.FieldElementType:
94+
Python object, as parsed from ``api_repr``.
95+
"""
96+
ifnotapi_repr:
97+
returnNone
98+
returncls(api_repr["type"].upper())
99+
100+
defto_api_repr(self)->dict:
101+
"""Construct the API resource representation of this field element type.
102+
103+
Returns:
104+
Dict[str, str]: Field element type represented as an API resource.
105+
"""
106+
returnself._properties
107+
108+
69109
classSchemaField(object):
70110
"""Describe a single field within a table schema.
71111
@@ -117,6 +157,12 @@ class SchemaField(object):
117157
- Struct or array composed with the above allowed functions, for example:
118158
119159
"[CURRENT_DATE(), DATE '2020-01-01'"]
160+
161+
range_element_type: FieldElementType, str, Optional
162+
The subtype of the RANGE, if the type of this field is RANGE. If
163+
the type is RANGE, this field is required. Possible values for the
164+
field element type of a RANGE include `DATE`, `DATETIME` and
165+
`TIMESTAMP`.
120166
"""
121167

122168
def__init__(
@@ -131,6 +177,7 @@ def __init__(
131177
precision:Union[int,_DefaultSentinel]=_DEFAULT_VALUE,
132178
scale:Union[int,_DefaultSentinel]=_DEFAULT_VALUE,
133179
max_length:Union[int,_DefaultSentinel]=_DEFAULT_VALUE,
180+
range_element_type:Union[FieldElementType,str,None]=None,
134181
):
135182
self._properties:Dict[str,Any]= {
136183
"name":name,
@@ -152,6 +199,11 @@ def __init__(
152199
self._properties["policyTags"]= (
153200
policy_tags.to_api_repr()ifpolicy_tagsisnotNoneelseNone
154201
)
202+
ifisinstance(range_element_type,str):
203+
self._properties["rangeElementType"]= {"type":range_element_type}
204+
ifisinstance(range_element_type,FieldElementType):
205+
self._properties["rangeElementType"]=range_element_type.to_api_repr()
206+
155207
self._fields=tuple(fields)
156208

157209
@staticmethod
@@ -186,6 +238,12 @@ def from_api_repr(cls, api_repr: dict) -> "SchemaField":
186238
ifpolicy_tagsisnotNoneandpolicy_tagsisnot_DEFAULT_VALUE:
187239
policy_tags=PolicyTagList.from_api_repr(policy_tags)
188240

241+
ifapi_repr.get("rangeElementType"):
242+
range_element_type=cast(dict,api_repr.get("rangeElementType"))
243+
element_type=range_element_type.get("type")
244+
else:
245+
element_type=None
246+
189247
returncls(
190248
field_type=field_type,
191249
fields=[cls.from_api_repr(f)forfinfields],
@@ -197,6 +255,7 @@ def from_api_repr(cls, api_repr: dict) -> "SchemaField":
197255
precision=cls.__get_int(api_repr,"precision"),
198256
scale=cls.__get_int(api_repr,"scale"),
199257
max_length=cls.__get_int(api_repr,"maxLength"),
258+
range_element_type=element_type,
200259
)
201260

202261
@property
@@ -252,6 +311,18 @@ def max_length(self):
252311
"""Optional[int]: Maximum length for the STRING or BYTES field."""
253312
returnself._properties.get("maxLength")
254313

314+
@property
315+
defrange_element_type(self):
316+
"""Optional[FieldElementType]: The subtype of the RANGE, if the
317+
type of this field is RANGE.
318+
319+
Must be set when ``type`` is `"RANGE"`. Must be one of `"DATE"`,
320+
`"DATETIME"` or `"TIMESTAMP"`.
321+
"""
322+
ifself._properties.get("rangeElementType"):
323+
ret=self._properties.get("rangeElementType")
324+
returnFieldElementType.from_api_repr(ret)
325+
255326
@property
256327
deffields(self):
257328
"""Optional[tuple]: Subfields contained in this field.

‎google/cloud/bigquery/version.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version__="3.14.1"
15+
__version__="3.15.0"

‎noxfile.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def mypy_samples(session):
219219
session.install(
220220
"types-mock",
221221
"types-pytz",
222-
"types-protobuf",
222+
"types-protobuf!=4.24.0.20240106",# This version causes an error: 'Module "google.oauth2" has no attribute "service_account"'
223223
"types-python-dateutil",
224224
"types-requests",
225225
"types-setuptools",

‎tests/data/schema.json‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@
8383
"mode" :"NULLABLE",
8484
"name" :"FavoriteNumber",
8585
"type" :"NUMERIC"
86+
},
87+
{
88+
"mode" :"NULLABLE",
89+
"name" :"TimeRange",
90+
"type" :"RANGE",
91+
"rangeElementType": {
92+
"type":"DATETIME"
93+
}
8694
}
8795
]
8896
}

‎tests/system/test_client.py‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,19 +1781,13 @@ def test_dbapi_fetch_w_bqstorage_client_large_result_set(self):
17811781
)
17821782

17831783
result_rows= [cursor.fetchone(),cursor.fetchone(),cursor.fetchone()]
1784-
17851784
field_name=operator.itemgetter(0)
17861785
fetched_data= [sorted(row.items(),key=field_name)forrowinresult_rows]
17871786
# Since DB API is not thread safe, only a single result stream should be
17881787
# requested by the BQ storage client, meaning that results should arrive
17891788
# in the sorted order.
17901789

17911790
expected_data= [
1792-
[
1793-
("by","pg"),
1794-
("id",1),
1795-
("timestamp",datetime.datetime(2006,10,9,18,21,51,tzinfo=UTC)),
1796-
],
17971791
[
17981792
("by","phyllis"),
17991793
("id",2),
@@ -1804,6 +1798,11 @@ def test_dbapi_fetch_w_bqstorage_client_large_result_set(self):
18041798
("id",3),
18051799
("timestamp",datetime.datetime(2006,10,9,18,40,33,tzinfo=UTC)),
18061800
],
1801+
[
1802+
("by","onebeerdave"),
1803+
("id",4),
1804+
("timestamp",datetime.datetime(2006,10,9,18,47,42,tzinfo=UTC)),
1805+
],
18071806
]
18081807

18091808
self.assertEqual(fetched_data,expected_data)

‎tests/unit/test_schema.py‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,36 @@ def test_constructor_subfields(self):
9797
self.assertEqual(field.fields[0],sub_field1)
9898
self.assertEqual(field.fields[1],sub_field2)
9999

100+
deftest_constructor_range(self):
101+
fromgoogle.cloud.bigquery.schemaimportFieldElementType
102+
103+
field=self._make_one(
104+
"test",
105+
"RANGE",
106+
mode="REQUIRED",
107+
description="Testing",
108+
range_element_type=FieldElementType("DATETIME"),
109+
)
110+
self.assertEqual(field.name,"test")
111+
self.assertEqual(field.field_type,"RANGE")
112+
self.assertEqual(field.mode,"REQUIRED")
113+
self.assertEqual(field.description,"Testing")
114+
self.assertEqual(field.range_element_type.element_type,"DATETIME")
115+
116+
deftest_constructor_range_str(self):
117+
field=self._make_one(
118+
"test",
119+
"RANGE",
120+
mode="REQUIRED",
121+
description="Testing",
122+
range_element_type="DATETIME",
123+
)
124+
self.assertEqual(field.name,"test")
125+
self.assertEqual(field.field_type,"RANGE")
126+
self.assertEqual(field.mode,"REQUIRED")
127+
self.assertEqual(field.description,"Testing")
128+
self.assertEqual(field.range_element_type.element_type,"DATETIME")
129+
100130
deftest_to_api_repr(self):
101131
fromgoogle.cloud.bigquery.schemaimportPolicyTagList
102132

@@ -160,6 +190,7 @@ def test_from_api_repr(self):
160190
self.assertEqual(field.fields[0].name,"bar")
161191
self.assertEqual(field.fields[0].field_type,"INTEGER")
162192
self.assertEqual(field.fields[0].mode,"NULLABLE")
193+
self.assertEqual(field.range_element_type,None)
163194

164195
deftest_from_api_repr_policy(self):
165196
field=self._get_target_class().from_api_repr(
@@ -178,6 +209,23 @@ def test_from_api_repr_policy(self):
178209
self.assertEqual(field.fields[0].field_type,"INTEGER")
179210
self.assertEqual(field.fields[0].mode,"NULLABLE")
180211

212+
deftest_from_api_repr_range(self):
213+
field=self._get_target_class().from_api_repr(
214+
{
215+
"mode":"nullable",
216+
"description":"test_range",
217+
"name":"foo",
218+
"type":"range",
219+
"rangeElementType": {"type":"DATETIME"},
220+
}
221+
)
222+
self.assertEqual(field.name,"foo")
223+
self.assertEqual(field.field_type,"RANGE")
224+
self.assertEqual(field.mode,"NULLABLE")
225+
self.assertEqual(field.description,"test_range")
226+
self.assertEqual(len(field.fields),0)
227+
self.assertEqual(field.range_element_type.element_type,"DATETIME")
228+
181229
deftest_from_api_repr_defaults(self):
182230
field=self._get_target_class().from_api_repr(
183231
{"name":"foo","type":"record"}
@@ -192,8 +240,10 @@ def test_from_api_repr_defaults(self):
192240
# _properties.
193241
self.assertIsNone(field.description)
194242
self.assertIsNone(field.policy_tags)
243+
self.assertIsNone(field.range_element_type)
195244
self.assertNotIn("description",field._properties)
196245
self.assertNotIn("policyTags",field._properties)
246+
self.assertNotIn("rangeElementType",field._properties)
197247

198248
deftest_name_property(self):
199249
name="lemon-ness"
@@ -566,6 +616,40 @@ def test___repr__evaluable_with_policy_tags(self):
566616
assertfield==evaled_field
567617

568618

619+
classTestFieldElementType(unittest.TestCase):
620+
@staticmethod
621+
def_get_target_class():
622+
fromgoogle.cloud.bigquery.schemaimportFieldElementType
623+
624+
returnFieldElementType
625+
626+
def_make_one(self,*args):
627+
returnself._get_target_class()(*args)
628+
629+
deftest_constructor(self):
630+
element_type=self._make_one("DATETIME")
631+
self.assertEqual(element_type.element_type,"DATETIME")
632+
self.assertEqual(element_type._properties["type"],"DATETIME")
633+
634+
deftest_to_api_repr(self):
635+
element_type=self._make_one("DATETIME")
636+
self.assertEqual(element_type.to_api_repr(), {"type":"DATETIME"})
637+
638+
deftest_from_api_repr(self):
639+
api_repr= {"type":"DATETIME"}
640+
expected_element_type=self._make_one("DATETIME")
641+
self.assertEqual(
642+
expected_element_type.element_type,
643+
self._get_target_class().from_api_repr(api_repr).element_type,
644+
)
645+
646+
deftest_from_api_repr_empty(self):
647+
self.assertEqual(None,self._get_target_class().from_api_repr({}))
648+
649+
deftest_from_api_repr_none(self):
650+
self.assertEqual(None,self._get_target_class().from_api_repr(None))
651+
652+
569653
# TODO: dedup with the same class in test_table.py.
570654
class_SchemaBase(object):
571655
def_verify_field(self,field,r_field):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp