Repository: googleapis/google-cloud-python

Issue:
job.py in bigquery does unnecessary client-side validation of data formats
The BigQuery engineering team may decide to expand the allowed formats for import and export, but the allowed values are hard-coded client side. Imports are limited to CSV, DATASTORE_BACKUP, NEWLINE_DELIMITED_JSON, AVRO, for example.

This means that if the BigQuery starts to allow other formats, users will be unable to use those new formats without updating their client. Moreover, there is no way for BigQuery to roll out new formats to a whitelisted set of users. 
(note this is not mere idle speculation and is currently impacting real users alpha testing a new format)

See code here:
[https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/bigquery/google/cloud/bigquery/job.py#L116][1]
and 
[https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/bigquery/google/cloud/bigquery/job.py#L139][2]

[1]: https://github.com/GoogleCloudPlatform/google-cloud-python/blob/6d7fae96d25a0a468683a5ab25a2f48014a16378/bigquery/google/cloud/bigquery/job.py#L116
[2]: https://github.com/GoogleCloudPlatform/google-cloud-python/blob/6d7fae96d25a0a468683a5ab25a2f48014a16378/bigquery/google/cloud/bigquery/job.py#L139


Discussion:

Resolving patch:
diff --git a/bigquery/google/cloud/bigquery/_helpers.py b/bigquery/google/cloud/bigquery/_helpers.py
--- a/bigquery/google/cloud/bigquery/_helpers.py
+++ b/bigquery/google/cloud/bigquery/_helpers.py
@@ -306,19 +306,9 @@ def _validate(self, value):
 class _EnumProperty(_ConfigurationProperty):
     """Pseudo-enumeration class.
 
-    Subclasses must define ``ALLOWED`` as a class-level constant:  it must
-    be a sequence of strings.
-
     :type name: str
     :param name:  name of the property.
     """
-    def _validate(self, value):
-        """Check that ``value`` is one of the allowed values.
-
-        :raises: ValueError if value is not allowed.
-        """
-        if value not in self.ALLOWED:
-            raise ValueError('Pass one of: %s' % ', '.join(self.ALLOWED))
 
 
 class UDFResource(object):
diff --git a/bigquery/google/cloud/bigquery/job.py b/bigquery/google/cloud/bigquery/job.py
--- a/bigquery/google/cloud/bigquery/job.py
+++ b/bigquery/google/cloud/bigquery/job.py
@@ -98,14 +98,12 @@ class Compression(_EnumProperty):
     """Pseudo-enum for ``compression`` properties."""
     GZIP = 'GZIP'
     NONE = 'NONE'
-    ALLOWED = (GZIP, NONE)
 
 
 class CreateDisposition(_EnumProperty):
     """Pseudo-enum for ``create_disposition`` properties."""
     CREATE_IF_NEEDED = 'CREATE_IF_NEEDED'
     CREATE_NEVER = 'CREATE_NEVER'
-    ALLOWED = (CREATE_IF_NEEDED, CREATE_NEVER)
 
 
 class DestinationFormat(_EnumProperty):
@@ -113,21 +111,18 @@ class DestinationFormat(_EnumProperty):
     CSV = 'CSV'
     NEWLINE_DELIMITED_JSON = 'NEWLINE_DELIMITED_JSON'
     AVRO = 'AVRO'
-    ALLOWED = (CSV, NEWLINE_DELIMITED_JSON, AVRO)
 
 
 class Encoding(_EnumProperty):
     """Pseudo-enum for ``encoding`` properties."""
     UTF_8 = 'UTF-8'
     ISO_8559_1 = 'ISO-8559-1'
-    ALLOWED = (UTF_8, ISO_8559_1)
 
 
 class QueryPriority(_EnumProperty):
     """Pseudo-enum for ``QueryJob.priority`` property."""
     INTERACTIVE = 'INTERACTIVE'
     BATCH = 'BATCH'
-    ALLOWED = (INTERACTIVE, BATCH)
 
 
 class SourceFormat(_EnumProperty):
@@ -136,7 +131,6 @@ class SourceFormat(_EnumProperty):
     DATASTORE_BACKUP = 'DATASTORE_BACKUP'
     NEWLINE_DELIMITED_JSON = 'NEWLINE_DELIMITED_JSON'
     AVRO = 'AVRO'
-    ALLOWED = (CSV, DATASTORE_BACKUP, NEWLINE_DELIMITED_JSON, AVRO)
 
 
 class WriteDisposition(_EnumProperty):
@@ -144,7 +138,6 @@ class WriteDisposition(_EnumProperty):
     WRITE_APPEND = 'WRITE_APPEND'
     WRITE_TRUNCATE = 'WRITE_TRUNCATE'
     WRITE_EMPTY = 'WRITE_EMPTY'
-    ALLOWED = (WRITE_APPEND, WRITE_TRUNCATE, WRITE_EMPTY)
 
 
 class _AsyncJob(google.cloud.future.polling.PollingFuture):


Test patch:
diff --git a/bigquery/tests/unit/test__helpers.py b/bigquery/tests/unit/test__helpers.py
--- a/bigquery/tests/unit/test__helpers.py
+++ b/bigquery/tests/unit/test__helpers.py
@@ -765,7 +765,7 @@ def _get_target_class():
     def test_it(self):
 
         class Sub(self._get_target_class()):
-            ALLOWED = ('FOO', 'BAR', 'BAZ')
+            pass
 
         class Configuration(object):
             _attr = None
@@ -777,9 +777,6 @@ def __init__(self):
                 self._configuration = Configuration()
 
         wrapper = Wrapper()
-        with self.assertRaises(ValueError):
-            wrapper.attr = 'BOGUS'
-
         wrapper.attr = 'FOO'
         self.assertEqual(wrapper.attr, 'FOO')
         self.assertEqual(wrapper._configuration._attr, 'FOO')