Skip to content
This repository was archived by the owner on Mar 16, 2026. It is now read-only.

Commit c2a4537

Browse files
hsheth2tswast
andauthored
Fetch table and column descriptions (#82)
* Fetch table and column descriptions * Reset coltype for unrecognized columns * add tests Co-authored-by: Tim Swast <swast@google.com>
1 parent 2145bdf commit c2a4537

5 files changed

Lines changed: 27 additions & 9 deletions

File tree

dev_requirements.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
sqlalchemy>=1.1.9
22
google-cloud-bigquery>=1.6.0
3-
future==0.16.0
3+
future==0.18.2
44

5-
pytest==3.2.2
6-
pytest-flake8==1.0.6
7-
pytz==2017.2
5+
pytest==6.2.2
6+
pytest-flake8==1.0.7
7+
pytz==2021.1

pybigquery/sqlalchemy_bigquery.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,16 +495,24 @@ def get_columns(self, connection, table_name, schema=None, **kw):
495495
coltype = _type_map[col.field_type]
496496
except KeyError:
497497
util.warn("Did not recognize type '%s' of column '%s'" % (col.field_type, col.name))
498+
coltype = types.NullType
498499

499500
result.append({
500501
'name': col.name,
501502
'type': types.ARRAY(coltype) if col.mode == 'REPEATED' else coltype,
502503
'nullable': col.mode == 'NULLABLE' or col.mode == 'REPEATED',
504+
'comment': col.description,
503505
'default': None,
504506
})
505507

506508
return result
507509

510+
def get_table_comment(self, connection, table_name, schema=None, **kw):
511+
table = self._get_table(connection, table_name, schema)
512+
return {
513+
'text': table.description,
514+
}
515+
508516
def get_foreign_keys(self, connection, table_name, schema=None, **kw):
509517
# BigQuery has no support for foreign keys.
510518
return []

scripts/load_test_data.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ bq rm -f -t test_pybigquery.sample_dml
99
bq rm -f -t test_pybigquery.sample_view
1010
bq rm -f -t test_pybigquery_location.sample_one_row
1111

12-
bq mk --table --schema=$(dirname $0)/schema.json --time_partitioning_field timestamp --clustering_fields integer,string test_pybigquery.sample
12+
bq mk --table --schema=$(dirname $0)/schema.json --time_partitioning_field timestamp --clustering_fields integer,string --description 'A sample table containing most data types.' test_pybigquery.sample
1313
bq mk --table --schema=$(dirname $0)/schema.json --time_partitioning_field timestamp --clustering_fields integer,string test_pybigquery_alt.sample_alt
1414
bq load --source_format=NEWLINE_DELIMITED_JSON --schema=$(dirname $0)/schema.json test_pybigquery.sample $(dirname $0)/sample.json
1515

scripts/schema.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"mode": "NULLABLE",
5353
"name": "record",
5454
"type": "RECORD",
55+
"description": "In Standard SQL this data type is a STRUCT<name STRING, age INT64>.",
5556
"fields": [
5657
{
5758
"mode": "NULLABLE",

test/test_sqlalchemy_bigquery.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,13 @@
8686
{'name': 'datetime', 'type': types.DATETIME(), 'nullable': True, 'default': None},
8787
{'name': 'time', 'type': types.TIME(), 'nullable': True, 'default': None},
8888
{'name': 'bytes', 'type': types.BINARY(), 'nullable': True, 'default': None},
89-
{'name': 'record', 'type': types.JSON(), 'nullable': True, 'default': None},
89+
{
90+
'name': 'record',
91+
'type': types.JSON(),
92+
'nullable': True,
93+
'default': None,
94+
'comment': 'In Standard SQL this data type is a STRUCT<name STRING, age INT64>.',
95+
},
9096
{'name': 'record.name', 'type': types.String(), 'nullable': True, 'default': None},
9197
{'name': 'record.age', 'type': types.Integer(), 'nullable': True, 'default': None},
9298
{'name': 'nested_record', 'type': types.JSON(), 'nullable': True, 'default': None},
@@ -225,8 +231,9 @@ def test_dataset_location(engine_with_location):
225231

226232
def test_reflect_select(table, table_using_test_dataset):
227233
for table in [table, table_using_test_dataset]:
228-
assert len(table.c) == 18
234+
assert table.comment == "A sample table containing most data types."
229235

236+
assert len(table.c) == 18
230237
assert isinstance(table.c.integer, Column)
231238
assert isinstance(table.c.integer.type, types.Integer)
232239
assert isinstance(table.c.timestamp.type, types.TIMESTAMP)
@@ -526,9 +533,10 @@ def test_get_columns(inspector, inspector_using_test_dataset):
526533
for columns in columns_queries:
527534
for i, col in enumerate(columns):
528535
sample_col = SAMPLE_COLUMNS[i]
536+
assert col['comment'] == sample_col.get('comment')
537+
assert col['default'] == sample_col['default']
529538
assert col['name'] == sample_col['name']
530539
assert col['nullable'] == sample_col['nullable']
531-
assert col['default'] == sample_col['default']
532540
assert col['type'].__class__.__name__ == sample_col['type'].__class__.__name__
533541

534542
columns_without_schema = inspector_using_test_dataset.get_columns('sample')
@@ -537,9 +545,10 @@ def test_get_columns(inspector, inspector_using_test_dataset):
537545
for columns in columns_queries:
538546
for i, col in enumerate(columns):
539547
sample_col = SAMPLE_COLUMNS[i]
548+
assert col['comment'] == sample_col.get('comment')
549+
assert col['default'] == sample_col['default']
540550
assert col['name'] == sample_col['name']
541551
assert col['nullable'] == sample_col['nullable']
542-
assert col['default'] == sample_col['default']
543552
assert col['type'].__class__.__name__ == sample_col['type'].__class__.__name__
544553

545554

0 commit comments

Comments
 (0)