diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a5b4d179..454d362f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ [1]: https://pypi.org/project/google-cloud-bigquery/#history +## [3.5.0](https://github.com/googleapis/python-bigquery/compare/v3.4.2...v3.5.0) (2023-01-31) + + +### Features + +* Add __str__ method to DatasetReference ([#1477](https://github.com/googleapis/python-bigquery/issues/1477)) ([f32df1f](https://github.com/googleapis/python-bigquery/commit/f32df1fb74e4aea24cd8a4099040ad2f7436e54d)) +* Add preserveAsciiControlCharacter to LoadJobConfig ([#1484](https://github.com/googleapis/python-bigquery/issues/1484)) ([bd1da9a](https://github.com/googleapis/python-bigquery/commit/bd1da9aa0a40b02b7d5409a0b094d8380e255c91)) + + +### Documentation + +* Adds snippet for creating table with external data config ([#1420](https://github.com/googleapis/python-bigquery/issues/1420)) ([f0ace2a](https://github.com/googleapis/python-bigquery/commit/f0ace2ac2307ef359511a235f80f5ce9e46264c1)) +* Revise delete label table code sample, add TODO to clean up sni… ([#1466](https://github.com/googleapis/python-bigquery/issues/1466)) ([0dab7d2](https://github.com/googleapis/python-bigquery/commit/0dab7d25ace4b63d2984485e7b0c5bb38f20476f)) +* **samples:** Table variable fix ([#1287](https://github.com/googleapis/python-bigquery/issues/1287)) ([a71888a](https://github.com/googleapis/python-bigquery/commit/a71888a60d1e5e5815ab459fe24368ad5b0d032a)) + ## [3.4.2](https://github.com/googleapis/python-bigquery/compare/v3.4.1...v3.4.2) (2023-01-13) diff --git a/docs/snippets.py b/docs/snippets.py index 85856eb3e..e1d9ae839 100644 --- a/docs/snippets.py +++ b/docs/snippets.py @@ -164,64 +164,6 @@ def test_create_partitioned_table(client, to_delete): "https://github.com/GoogleCloudPlatform/google-cloud-python/issues/5589" ) ) -def test_manage_table_labels(client, to_delete): - dataset_id = "label_table_dataset_{}".format(_millis()) - table_id = "label_table_{}".format(_millis()) - project = client.project - dataset_ref = bigquery.DatasetReference(project, dataset_id) - dataset = bigquery.Dataset(dataset_ref) - client.create_dataset(dataset) - to_delete.append(dataset) - - table = bigquery.Table(dataset.table(table_id), schema=SCHEMA) - - labels = {"color": "green"} - table.labels = labels - table = client.create_table(table) - - # TODO(Mattix23): After code sample is updated from cloud.google.com delete this - - # [START bigquery_get_table_labels] - # from google.cloud import bigquery - # client = bigquery.Client() - # dataset_id = 'my_dataset' - # table_id = 'my_table' - - project = client.project - dataset_ref = bigquery.DatasetReference(project, dataset_id) - table_ref = dataset_ref.table(table_id) - table = client.get_table(table_ref) # API Request - - # View table labels - print("Table ID: {}".format(table_id)) - print("Labels:") - if table.labels: - for label, value in table.labels.items(): - print("\t{}: {}".format(label, value)) - else: - print("\tTable has no labels defined.") - # [END bigquery_get_table_labels] - assert table.labels == labels - - # [START bigquery_delete_label_table] - # from google.cloud import bigquery - # client = bigquery.Client() - # project = client.project - # dataset_ref = bigquery.DatasetReference(project, dataset_id) - # table_ref = dataset_ref.table('my_table') - # table = client.get_table(table_ref) # API request - - # This example table starts with one label - assert table.labels == {"color": "green"} - # To delete a label from a table, set its value to None - table.labels["color"] = None - - table = client.update_table(table, ["labels"]) # API request - - assert table.labels == {} - # [END bigquery_delete_label_table] - - @pytest.mark.skip( reason=( "update_table() is flaky " diff --git a/docs/usage/tables.rst b/docs/usage/tables.rst index d924fe214..105e93637 100644 --- a/docs/usage/tables.rst +++ b/docs/usage/tables.rst @@ -58,6 +58,15 @@ Create an empty table with the :start-after: [START bigquery_create_table] :end-before: [END bigquery_create_table] +Create a table using an external data source with the +:func:`~google.cloud.bigquery.client.Client.create_table` method: + +.. literalinclude:: ../samples/create_table_external_data_configuration.py + :language: python + :dedent: 4 + :start-after: [START bigquery_create_table_external_data_configuration] + :end-before: [END bigquery_create_table_external_data_configuration] + Create a clustered table with the :func:`~google.cloud.bigquery.client.Client.create_table` method: diff --git a/google/cloud/bigquery/dataset.py b/google/cloud/bigquery/dataset.py index c30204067..0edd29359 100644 --- a/google/cloud/bigquery/dataset.py +++ b/google/cloud/bigquery/dataset.py @@ -215,6 +215,9 @@ def __ne__(self, other): def __hash__(self): return hash(self._key()) + def __str__(self): + return f"{self.project}.{self._dataset_id}" + def __repr__(self): return "DatasetReference{}".format(self._key()) diff --git a/google/cloud/bigquery/job/load.py b/google/cloud/bigquery/job/load.py index 5c7f26841..14a7fa30b 100644 --- a/google/cloud/bigquery/job/load.py +++ b/google/cloud/bigquery/job/load.py @@ -311,6 +311,19 @@ def null_marker(self): def null_marker(self, value): self._set_sub_prop("nullMarker", value) + @property + def preserve_ascii_control_characters(self): + """Optional[bool]: Preserves the embedded ASCII control characters when sourceFormat is set to CSV. + + See: + https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfigurationLoad.FIELDS.preserve_ascii_control_characters + """ + return self._get_sub_prop("preserveAsciiControlCharacters") + + @preserve_ascii_control_characters.setter + def preserve_ascii_control_characters(self, value): + self._set_sub_prop("preserveAsciiControlCharacters", bool(value)) + @property def projection_fields(self) -> Optional[List[str]]: """Optional[List[str]]: If diff --git a/google/cloud/bigquery/version.py b/google/cloud/bigquery/version.py index d38bb4619..13194aa56 100644 --- a/google/cloud/bigquery/version.py +++ b/google/cloud/bigquery/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "3.4.2" +__version__ = "3.5.0" diff --git a/samples/browse_table_data.py b/samples/browse_table_data.py index 6a56253bf..74b903aa3 100644 --- a/samples/browse_table_data.py +++ b/samples/browse_table_data.py @@ -47,7 +47,7 @@ def browse_table_data(table_id: str) -> None: print("Downloaded {} rows from table {}".format(len(rows), table_id)) # Print row data in tabular format. - rows_iter = client.list_rows(table, max_results=10) + rows_iter = client.list_rows(table_id, max_results=10) format_string = "{!s:<16} " * len(rows_iter.schema) field_names = [field.name for field in rows_iter.schema] print(format_string.format(*field_names)) # Prints column headers. diff --git a/samples/create_table_external_data_configuration.py b/samples/create_table_external_data_configuration.py new file mode 100644 index 000000000..068f91555 --- /dev/null +++ b/samples/create_table_external_data_configuration.py @@ -0,0 +1,66 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_table_external_data_configuration( + table_id: str, +) -> None: + """Create a table using an external data source""" + orig_table_id = table_id + # [START bigquery_create_table_external_data_configuration] + # [START bigquery_create_external_table_definition] + from google.cloud import bigquery + + # Construct a BigQuery client object. + client = bigquery.Client() + + # TODO(developer): Set table_id to the ID of the table to create. + table_id = "your-project.your_dataset.your_table_name" + # [END bigquery_create_table_external_data_configuration] + table_id = orig_table_id + # [START bigquery_create_table_external_data_configuration] + + # TODO(developer): Set the external source format of your table. + # Note that the set of allowed values for external data sources is + # different than the set used for loading data (see :class:`~google.cloud.bigquery.job.SourceFormat`). + external_source_format = "AVRO" + + # TODO(developer): Set the source_uris to point to your data in Google Cloud + source_uris = [ + "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/a-twitter.avro", + "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/b-twitter.avro", + "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/c-twitter.avro", + ] + + # Create ExternalConfig object with external source format + external_config = bigquery.ExternalConfig(external_source_format) + # Set source_uris that point to your data in Google Cloud + external_config.source_uris = source_uris + + # TODO(developer) You have the option to set a reference_file_schema_uri, which points to + # a reference file for the table schema + reference_file_schema_uri = "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/b-twitter.avro" + + external_config.reference_file_schema_uri = reference_file_schema_uri + # [END bigquery_create_external_table_definition] + + table = bigquery.Table(table_id) + # Set the external data configuration of the table + table.external_data_configuration = external_config + table = client.create_table(table) # Make an API request. + + print( + f"Created table with external source format {table.external_data_configuration.source_format}" + ) + # [END bigquery_create_table_external_data_configuration] diff --git a/samples/geography/requirements-test.txt b/samples/geography/requirements-test.txt index 1e6b7c5ea..100e0639c 100644 --- a/samples/geography/requirements-test.txt +++ b/samples/geography/requirements-test.txt @@ -1,2 +1,2 @@ -pytest==7.2.0 +pytest==7.2.1 mock==5.0.1 diff --git a/samples/geography/requirements.txt b/samples/geography/requirements.txt index 0f475e0fd..284614d17 100644 --- a/samples/geography/requirements.txt +++ b/samples/geography/requirements.txt @@ -7,38 +7,38 @@ click-plugins==1.1.1 cligj==0.7.2 dataclasses==0.8; python_version < '3.7' db-dtypes==1.0.5 -Fiona==1.8.22 -geojson==2.5.0 +Fiona==1.9.0 +geojson==3.0.0 geopandas===0.10.2; python_version == '3.7' geopandas==0.12.2; python_version >= '3.8' google-api-core==2.11.0 google-auth==2.16.0 -google-cloud-bigquery==3.4.1 -google-cloud-bigquery-storage==2.18.0 +google-cloud-bigquery==3.4.2 +google-cloud-bigquery-storage==2.18.1 google-cloud-core==2.3.2 google-crc32c==1.5.0 -google-resumable-media==2.4.0 +google-resumable-media==2.4.1 googleapis-common-protos==1.58.0 grpcio==1.51.1 idna==3.4 libcst==0.4.9 munch==2.5.0 mypy-extensions==0.4.3 -packaging==21.3 +packaging==23.0 pandas===1.3.5; python_version == '3.7' -pandas==1.5.2; python_version >= '3.8' +pandas==1.5.3; python_version >= '3.8' proto-plus==1.22.2 -pyarrow==10.0.1 +pyarrow==11.0.0 pyasn1==0.4.8 pyasn1-modules==0.2.8 pycparser==2.21 pyparsing==3.0.9 python-dateutil==2.8.2 -pytz==2022.7 +pytz==2022.7.1 PyYAML==6.0 requests==2.28.2 rsa==4.9 -Shapely==2.0.0 +Shapely==2.0.1 six==1.16.0 typing-extensions==4.4.0 typing-inspect==0.8.0 diff --git a/samples/magics/requirements-test.txt b/samples/magics/requirements-test.txt index 56aa0f432..e8f3982c7 100644 --- a/samples/magics/requirements-test.txt +++ b/samples/magics/requirements-test.txt @@ -1,3 +1,3 @@ google-cloud-testutils==1.3.3 -pytest==7.2.0 +pytest==7.2.1 mock==5.0.1 diff --git a/samples/magics/requirements.txt b/samples/magics/requirements.txt index 463829c8f..2446aa5e8 100644 --- a/samples/magics/requirements.txt +++ b/samples/magics/requirements.txt @@ -1,15 +1,15 @@ db-dtypes==1.0.5 -google-cloud-bigquery-storage==2.18.0 +google-cloud-bigquery-storage==2.18.1 google-auth-oauthlib==0.8.0 grpcio==1.51.1 ipywidgets==8.0.4 ipython===7.31.1; python_version == '3.7' ipython===8.0.1; python_version == '3.8' -ipython==8.8.0; python_version >= '3.9' +ipython==8.9.0; python_version >= '3.9' matplotlib===3.5.3; python_version == '3.7' matplotlib==3.6.3; python_version >= '3.8' pandas===1.3.5; python_version == '3.7' -pandas==1.5.2; python_version >= '3.8' -pyarrow==10.0.1 -pytz==2022.7 +pandas==1.5.3; python_version >= '3.8' +pyarrow==11.0.0 +pytz==2022.7.1 typing-extensions==4.4.0 diff --git a/samples/snippets/delete_label_table.py b/samples/snippets/delete_label_table.py new file mode 100644 index 000000000..0e9eaaf8f --- /dev/null +++ b/samples/snippets/delete_label_table.py @@ -0,0 +1,43 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.cloud import bigquery + + +def delete_label_table(table_id: str, label_key: str) -> bigquery.Table: + orig_table_id = table_id + orig_label_key = label_key + # [START bigquery_delete_label_table] + from google.cloud import bigquery + + client = bigquery.Client() + + # TODO(dev): Change table_id to the full name of the table you wish to delete from. + table_id = "your-project.your_dataset.your_table_name" + # TODO(dev): Change label_key to the name of the label you want to remove. + label_key = "color" + # [END bigquery_delete_label_table] + table_id = orig_table_id + label_key = orig_label_key + # [START bigquery_delete_label_table] + table = client.get_table(table_id) # API request + + # To delete a label from a table, set its value to None + table.labels[label_key] = None + + table = client.update_table(table, ["labels"]) # API request + + print(f"Deleted label '{label_key}' from {table_id}.") + # [END bigquery_delete_label_table] + return table diff --git a/samples/snippets/delete_label_table_test.py b/samples/snippets/delete_label_table_test.py new file mode 100644 index 000000000..54acae77f --- /dev/null +++ b/samples/snippets/delete_label_table_test.py @@ -0,0 +1,34 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing + +import delete_label_table + +if typing.TYPE_CHECKING: + import pytest + + +def test_delete_label_table( + capsys: "pytest.CaptureFixture[str]", + table_id: str, +) -> None: + + table = delete_label_table.delete_label_table(table_id, "color") + + out, _ = capsys.readouterr() + assert "Deleted" in out + assert "color" in out + assert table_id in out + assert table.labels is None or "color" not in table.labels diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt index 56aa0f432..e8f3982c7 100644 --- a/samples/snippets/requirements-test.txt +++ b/samples/snippets/requirements-test.txt @@ -1,3 +1,3 @@ google-cloud-testutils==1.3.3 -pytest==7.2.0 +pytest==7.2.1 mock==5.0.1 diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index 1ecf3fc45..a85653d42 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,16 +1,16 @@ db-dtypes==1.0.5 -google-cloud-bigquery==3.4.1 -google-cloud-bigquery-storage==2.18.0 +google-cloud-bigquery==3.4.2 +google-cloud-bigquery-storage==2.18.1 google-auth-oauthlib==0.8.0 grpcio==1.51.1 ipywidgets==8.0.4 ipython===7.31.1; python_version == '3.7' ipython===8.0.1; python_version == '3.8' -ipython==8.8.0; python_version >= '3.9' +ipython==8.9.0; python_version >= '3.9' matplotlib===3.5.3; python_version == '3.7' matplotlib==3.6.3; python_version >= '3.8' pandas===1.3.5; python_version == '3.7' -pandas==1.5.2; python_version >= '3.8' -pyarrow==10.0.1 -pytz==2022.7 +pandas==1.5.3; python_version >= '3.8' +pyarrow==11.0.0 +pytz==2022.7.1 typing-extensions==4.4.0 diff --git a/samples/tests/conftest.py b/samples/tests/conftest.py index b7a2ad587..99bd2e367 100644 --- a/samples/tests/conftest.py +++ b/samples/tests/conftest.py @@ -13,7 +13,7 @@ # limitations under the License. import datetime -from typing import Iterator +from typing import Iterator, List import uuid import google.auth @@ -47,6 +47,22 @@ def random_table_id(dataset_id: str) -> str: return "{}.{}".format(dataset_id, random_table_id) +@pytest.fixture +def avro_source_uris() -> List[str]: + avro_source_uris = [ + "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/a-twitter.avro", + "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/b-twitter.avro", + "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/c-twitter.avro", + ] + return avro_source_uris + + +@pytest.fixture +def reference_file_schema_uri() -> str: + reference_file_schema_uri = "gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/b-twitter.avro" + return reference_file_schema_uri + + @pytest.fixture def random_dataset_id(client: bigquery.Client) -> Iterator[str]: now = datetime.datetime.now() diff --git a/samples/tests/test_create_table_external_data_configuration.py b/samples/tests/test_create_table_external_data_configuration.py new file mode 100644 index 000000000..bf4cf17d4 --- /dev/null +++ b/samples/tests/test_create_table_external_data_configuration.py @@ -0,0 +1,32 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing + +from .. import create_table_external_data_configuration + +if typing.TYPE_CHECKING: + import pytest + + +def test_create_table_external_data_configuration( + capsys: "pytest.CaptureFixture[str]", + random_table_id: str, +) -> None: + + create_table_external_data_configuration.create_table_external_data_configuration( + random_table_id + ) + out, _ = capsys.readouterr() + assert "Created table with external source format AVRO" in out diff --git a/tests/system/test_client.py b/tests/system/test_client.py index 575898209..14a9b04d4 100644 --- a/tests/system/test_client.py +++ b/tests/system/test_client.py @@ -335,57 +335,6 @@ def test_create_table(self): self.assertTrue(_table_exists(table)) self.assertEqual(table.table_id, table_id) - def test_create_table_with_policy(self): - from google.cloud.bigquery.schema import PolicyTagList - - dataset = self.temp_dataset(_make_dataset_id("create_table_with_policy")) - table_id = "test_table" - policy_1 = PolicyTagList( - names=[ - "projects/{}/locations/us/taxonomies/1/policyTags/2".format( - Config.CLIENT.project - ), - ] - ) - policy_2 = PolicyTagList( - names=[ - "projects/{}/locations/us/taxonomies/3/policyTags/4".format( - Config.CLIENT.project - ), - ] - ) - - schema = [ - bigquery.SchemaField("full_name", "STRING", mode="REQUIRED"), - bigquery.SchemaField( - "secret_int", "INTEGER", mode="REQUIRED", policy_tags=policy_1 - ), - ] - table_arg = Table(dataset.table(table_id), schema=schema) - self.assertFalse(_table_exists(table_arg)) - - table = helpers.retry_403(Config.CLIENT.create_table)(table_arg) - self.to_delete.insert(0, table) - - self.assertTrue(_table_exists(table)) - self.assertEqual(policy_1, table.schema[1].policy_tags) - - # Amend the schema to replace the policy tags - new_schema = table.schema[:] - old_field = table.schema[1] - new_schema[1] = bigquery.SchemaField( - name=old_field.name, - field_type=old_field.field_type, - mode=old_field.mode, - description=old_field.description, - fields=old_field.fields, - policy_tags=policy_2, - ) - - table.schema = new_schema - table2 = Config.CLIENT.update_table(table, ["schema"]) - self.assertEqual(policy_2, table2.schema[1].policy_tags) - def test_create_table_with_real_custom_policy(self): from google.cloud.bigquery.schema import PolicyTagList diff --git a/tests/unit/job/test_load_config.py b/tests/unit/job/test_load_config.py index 5a0c5a83f..7f77fc085 100644 --- a/tests/unit/job/test_load_config.py +++ b/tests/unit/job/test_load_config.py @@ -424,6 +424,20 @@ def test_null_marker_setter(self): config.null_marker = null_marker self.assertEqual(config._properties["load"]["nullMarker"], null_marker) + def test_preserve_ascii_control_characters_missing(self): + config = self._get_target_class()() + self.assertIsNone(config.preserve_ascii_control_characters) + + def test_preserve_ascii_control_characters_hit(self): + config = self._get_target_class()() + config._properties["load"]["preserveAsciiControlCharacters"] = True + self.assertTrue(config.preserve_ascii_control_characters) + + def test_preserve_ascii_control_characters_setter(self): + config = self._get_target_class()() + config.preserve_ascii_control_characters = True + self.assertTrue(config._properties["load"]["preserveAsciiControlCharacters"]) + def test_projection_fields_miss(self): config = self._get_target_class()() self.assertIsNone(config.projection_fields) diff --git a/tests/unit/test_dataset.py b/tests/unit/test_dataset.py index 856674daf..5e26a0c03 100644 --- a/tests/unit/test_dataset.py +++ b/tests/unit/test_dataset.py @@ -622,6 +622,10 @@ def test___repr__(self): expected = "DatasetReference('project1', 'dataset1')" self.assertEqual(repr(dataset), expected) + def test___str__(self): + dataset = self._make_one("project1", "dataset1") + self.assertEqual(str(dataset), "project1.dataset1") + class TestDataset(unittest.TestCase): from google.cloud.bigquery.dataset import DatasetReference