diff --git a/google/cloud/bigquery/job/base.py b/google/cloud/bigquery/job/base.py index a6267be41..78df9142f 100644 --- a/google/cloud/bigquery/job/base.py +++ b/google/cloud/bigquery/job/base.py @@ -26,6 +26,7 @@ from google.cloud.bigquery import _helpers from google.cloud.bigquery.retry import DEFAULT_RETRY +from google.cloud.bigquery._helpers import _int_or_none if typing.TYPE_CHECKING: # pragma: NO COVER from google.api_core import retry as retries @@ -171,6 +172,37 @@ def __setattr__(self, name, value): ) super(_JobConfig, self).__setattr__(name, value) + @property + def job_timeout_ms(self): + """Optional parameter. Job timeout in milliseconds. If this time limit is exceeded, BigQuery might attempt to stop the job. + https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfiguration.FIELDS.job_timeout_ms + e.g. + + job_config = bigquery.QueryJobConfig( job_timeout_ms = 5000 ) + or + job_config.job_timeout_ms = 5000 + + Raises: + ValueError: If ``value`` type is invalid. + """ + + # None as this is an optional parameter. + if self._properties.get("jobTimeoutMs"): + return self._properties["jobTimeoutMs"] + return None + + @job_timeout_ms.setter + def job_timeout_ms(self, value): + try: + value = _int_or_none(value) + except ValueError as err: + raise ValueError("Pass an int for jobTimeoutMs, e.g. 5000").with_traceback( + err.__traceback__ + ) + + """ Docs indicate a string is expected by the API """ + self._properties["jobTimeoutMs"] = str(value) + @property def labels(self): """Dict[str, str]: Labels for the job. diff --git a/noxfile.py b/noxfile.py index 703e36cbb..7cf5f6021 100644 --- a/noxfile.py +++ b/noxfile.py @@ -193,7 +193,12 @@ def system(session): session.install("-e", f".{extras}", "-c", constraints_path) # Run py.test against the system tests. - session.run("py.test", "--quiet", os.path.join("tests", "system"), *session.posargs) + session.run( + "py.test", + "--quiet", + os.path.join("tests", "system"), + *session.posargs, + ) @nox.session(python=DEFAULT_PYTHON_VERSION) diff --git a/tests/unit/job/test_base.py b/tests/unit/job/test_base.py index a662e92d4..5635d0e32 100644 --- a/tests/unit/job/test_base.py +++ b/tests/unit/job/test_base.py @@ -1228,3 +1228,18 @@ def test_labels_setter(self): job_config = self._make_one() job_config.labels = labels self.assertEqual(job_config._properties["labels"], labels) + + def test_job_timeout_ms_raises_valueerror(self): + # Confirm that attempting to set a non-integer values will raise an Error. + with pytest.raises(ValueError): + job_config = self._make_one() + job_config.job_timeout_ms = "WillRaiseError" + + def test_job_timeout_ms(self): + # Confirm that default status is None. + job_config = self._make_one() + assert job_config.job_timeout_ms is None + + # Confirm that integers get converted to strings. + job_config.job_timeout_ms = 5000 + assert job_config.job_timeout_ms == "5000" # int is converted to string