diff --git a/bigquery/google/cloud/bigquery/dataset.py b/bigquery/google/cloud/bigquery/dataset.py index b290ec7bb49e..b5f2ef615fac 100644 --- a/bigquery/google/cloud/bigquery/dataset.py +++ b/bigquery/google/cloud/bigquery/dataset.py @@ -210,6 +210,37 @@ def from_api_repr(cls, resource): dataset_id = resource['datasetId'] return cls(project, dataset_id) + @classmethod + def from_string(cls, full_dataset_id): + """Construct a dataset reference from fully-qualified dataset ID. + + Args: + full_dataset_id (str): + A fully-qualified dataset ID in standard SQL format. Must + included both the project ID and the dataset ID, separated by + ``.``. + + Returns: + DatasetReference: + Dataset reference parsed from ``full_dataset_id``. + + Examples: + >>> DatasetReference.from_string('my-project-id.some_dataset') + DatasetReference('my-project-id', 'some_dataset') + + Raises: + ValueError: + If ``full_dataset_id`` is not a fully-qualified dataset ID in + standard SQL format. + """ + parts = full_dataset_id.split('.') + if len(parts) != 2: + raise ValueError( + 'full_dataset_id must be a fully-qualified dataset ID in ' + 'standard SQL format. e.g. "project.dataset_id", got ' + '{}'.format(full_dataset_id)) + return cls(*parts) + def to_api_repr(self): """Construct the API resource representation of this dataset reference @@ -450,6 +481,30 @@ def labels(self, value): raise ValueError("Pass a dict") self._properties['labels'] = value + @classmethod + def from_string(cls, full_dataset_id): + """Construct a dataset from fully-qualified dataset ID. + + Args: + full_dataset_id (str): + A fully-qualified dataset ID in standard SQL format. Must + included both the project ID and the dataset ID, separated by + ``.``. + + Returns: + Dataset: Dataset parsed from ``full_dataset_id``. + + Examples: + >>> Dataset.from_string('my-project-id.some_dataset') + Dataset(DatasetReference('my-project-id', 'some_dataset')) + + Raises: + ValueError: + If ``full_dataset_id`` is not a fully-qualified dataset ID in + standard SQL format. + """ + return cls(DatasetReference.from_string(full_dataset_id)) + @classmethod def from_api_repr(cls, resource): """Factory: construct a dataset given its API representation @@ -508,6 +563,9 @@ def table(self, table_id): """ return TableReference(self.reference, table_id) + def __repr__(self): + return 'Dataset({})'.format(repr(self.reference)) + class DatasetListItem(object): """A read-only dataset resource from a list operation. diff --git a/bigquery/google/cloud/bigquery/table.py b/bigquery/google/cloud/bigquery/table.py index 61be2004531b..e5c76370d364 100644 --- a/bigquery/google/cloud/bigquery/table.py +++ b/bigquery/google/cloud/bigquery/table.py @@ -166,6 +166,39 @@ def path(self): return '/projects/%s/datasets/%s/tables/%s' % ( self._project, self._dataset_id, self._table_id) + @classmethod + def from_string(cls, full_table_id): + """Construct a table reference from fully-qualified table ID. + + Args: + full_table_id (str): + A fully-qualified table ID in standard SQL format. Must + included a project ID, dataset ID, and table ID, each + separated by ``.``. + + Returns: + TableReference: Table reference parsed from ``full_table_id``. + + Examples: + >>> TableReference.from_string('my-project.mydataset.mytable') + TableRef...(DatasetRef...('my-project', 'mydataset'), 'mytable') + + Raises: + ValueError: + If ``full_table_id`` is not a fully-qualified table ID in + standard SQL format. + """ + from google.cloud.bigquery.dataset import DatasetReference + + parts = full_table_id.split('.') + if len(parts) != 3: + raise ValueError( + 'full_table_id must be a fully-qualified table ID in ' + 'standard SQL format. e.g. "project.dataset.table", got ' + '{}'.format(full_table_id)) + + return cls(DatasetReference(parts[0], parts[1]), parts[2]) + @classmethod def from_api_repr(cls, resource): """Factory: construct a table reference given its API representation @@ -223,7 +256,10 @@ def __hash__(self): return hash(self._key()) def __repr__(self): - return 'TableReference{}'.format(self._key()) + from google.cloud.bigquery.dataset import DatasetReference + dataset_ref = DatasetReference(self._project, self._dataset_id) + return "TableReference({}, '{}')".format( + repr(dataset_ref), self._table_id) class Table(object): @@ -609,6 +645,30 @@ def external_data_configuration(self, value): api_repr = value.to_api_repr() self._properties['externalDataConfiguration'] = api_repr + @classmethod + def from_string(cls, full_table_id): + """Construct a table from fully-qualified table ID. + + Args: + full_table_id (str): + A fully-qualified table ID in standard SQL format. Must + included a project ID, dataset ID, and table ID, each + separated by ``.``. + + Returns: + Table: Table parsed from ``full_table_id``. + + Examples: + >>> Table.from_string('my-project.mydataset.mytable') + Table(TableRef...(D...('my-project', 'mydataset'), 'mytable')) + + Raises: + ValueError: + If ``full_table_id`` is not a fully-qualified table ID in + standard SQL format. + """ + return cls(TableReference.from_string(full_table_id)) + @classmethod def from_api_repr(cls, resource): """Factory: construct a table given its API representation @@ -668,6 +728,9 @@ def _build_resource(self, filter_fields): return partial + def __repr__(self): + return 'Table({})'.format(repr(self.reference)) + class TableListItem(object): """A read-only table resource from a list operation. diff --git a/bigquery/tests/unit/test_dataset.py b/bigquery/tests/unit/test_dataset.py index 1dbf91f46e27..314010202676 100644 --- a/bigquery/tests/unit/test_dataset.py +++ b/bigquery/tests/unit/test_dataset.py @@ -165,10 +165,10 @@ def test_to_api_repr(self): }) def test_from_api_repr(self): - from google.cloud.bigquery.dataset import DatasetReference + cls = self._get_target_class() expected = self._make_one('project_1', 'dataset_1') - got = DatasetReference.from_api_repr( + got = cls.from_api_repr( { 'projectId': 'project_1', 'datasetId': 'dataset_1', @@ -176,6 +176,17 @@ def test_from_api_repr(self): self.assertEqual(expected, got) + def test_from_string(self): + cls = self._get_target_class() + got = cls.from_string('string-project.string_dataset') + self.assertEqual(got.project, 'string-project') + self.assertEqual(got.dataset_id, 'string_dataset') + + def test_from_string_legacy_string(self): + cls = self._get_target_class() + with self.assertRaises(ValueError): + cls.from_string('string-project:string_dataset') + def test___eq___wrong_type(self): dataset = self._make_one('project_1', 'dataset_1') other = object() @@ -484,6 +495,17 @@ def test_to_api_repr_w_custom_field(self): } self.assertEqual(resource, exp_resource) + def test_from_string(self): + cls = self._get_target_class() + got = cls.from_string('string-project.string_dataset') + self.assertEqual(got.project, 'string-project') + self.assertEqual(got.dataset_id, 'string_dataset') + + def test_from_string_legacy_string(self): + cls = self._get_target_class() + with self.assertRaises(ValueError): + cls.from_string('string-project:string_dataset') + def test__build_resource_w_custom_field(self): dataset = self._make_one(self.DS_REF) dataset._properties['newAlphaProperty'] = 'unreleased property' @@ -510,6 +532,12 @@ def test_table(self): self.assertEqual(table.dataset_id, self.DS_ID) self.assertEqual(table.project, self.PROJECT) + def test___repr__(self): + from google.cloud.bigquery.dataset import DatasetReference + dataset = self._make_one(DatasetReference('project1', 'dataset1')) + expected = "Dataset(DatasetReference('project1', 'dataset1'))" + self.assertEqual(repr(dataset), expected) + class TestDatasetListItem(unittest.TestCase): diff --git a/bigquery/tests/unit/test_table.py b/bigquery/tests/unit/test_table.py index 7482e9f88ea3..db62782e1ebd 100644 --- a/bigquery/tests/unit/test_table.py +++ b/bigquery/tests/unit/test_table.py @@ -134,6 +134,23 @@ def test_from_api_repr(self): self.assertEqual(expected, got) + def test_from_string(self): + cls = self._get_target_class() + got = cls.from_string('string-project.string_dataset.string_table') + self.assertEqual(got.project, 'string-project') + self.assertEqual(got.dataset_id, 'string_dataset') + self.assertEqual(got.table_id, 'string_table') + + def test_from_string_legacy_string(self): + cls = self._get_target_class() + with self.assertRaises(ValueError): + cls.from_string('string-project:string_dataset.string_table') + + def test_from_string_not_fully_qualified(self): + cls = self._get_target_class() + with self.assertRaises(ValueError): + cls.from_string('string_dataset.string_table') + def test___eq___wrong_type(self): from google.cloud.bigquery.dataset import DatasetReference dataset_ref = DatasetReference('project_1', 'dataset_1') @@ -193,7 +210,10 @@ def test___hash__not_equals(self): def test___repr__(self): dataset = DatasetReference('project1', 'dataset1') table1 = self._make_one(dataset, 'table1') - expected = "TableReference('project1', 'dataset1', 'table1')" + expected = ( + "TableReference(DatasetReference('project1', 'dataset1'), " + "'table1')" + ) self.assertEqual(repr(table1), expected) @@ -634,6 +654,23 @@ def test_labels_setter_bad_value(self): with self.assertRaises(ValueError): table.labels = 12345 + def test_from_string(self): + cls = self._get_target_class() + got = cls.from_string('string-project.string_dataset.string_table') + self.assertEqual(got.project, 'string-project') + self.assertEqual(got.dataset_id, 'string_dataset') + self.assertEqual(got.table_id, 'string_table') + + def test_from_string_legacy_string(self): + cls = self._get_target_class() + with self.assertRaises(ValueError): + cls.from_string('string-project:string_dataset.string_table') + + def test_from_string_not_fully_qualified(self): + cls = self._get_target_class() + with self.assertRaises(ValueError): + cls.from_string('string_dataset.string_table') + def test_from_api_repr_missing_identity(self): self._setUpConstants() RESOURCE = {} @@ -837,6 +874,17 @@ def test_encryption_configuration_setter(self): table.encryption_configuration = None self.assertIsNone(table.encryption_configuration) + def test___repr__(self): + from google.cloud.bigquery.table import TableReference + dataset = DatasetReference('project1', 'dataset1') + table1 = self._make_one(TableReference(dataset, 'table1')) + expected = ( + "Table(TableReference(" + "DatasetReference('project1', 'dataset1'), " + "'table1'))" + ) + self.assertEqual(repr(table1), expected) + class Test_row_from_mapping(unittest.TestCase, _SchemaBase):