From 71e9d2b8f96614221629d323857ad4225d0cc452 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Fri, 17 Apr 2020 14:57:35 -0400 Subject: [PATCH 01/12] Add details to failed job error message --- strawberryfields/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strawberryfields/engine.py b/strawberryfields/engine.py index 70f95d32f..ecf57bc28 100644 --- a/strawberryfields/engine.py +++ b/strawberryfields/engine.py @@ -548,7 +548,7 @@ def run(self, program: Program, *, compile_options=None, **kwargs) -> Optional[R if job.status == "failed": message = ( "The remote job %s failed due to an internal " - "server error. Please try again." % job.id + "server error. Please try again. (%s)" % (job.id, job.meta) ) self.log.error(message) From e1ec6b0a68d92374eabd53b9856e2675f1cf9dcb Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Fri, 17 Apr 2020 15:14:27 -0400 Subject: [PATCH 02/12] Remove brackets --- strawberryfields/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strawberryfields/engine.py b/strawberryfields/engine.py index ecf57bc28..0228b257a 100644 --- a/strawberryfields/engine.py +++ b/strawberryfields/engine.py @@ -548,7 +548,7 @@ def run(self, program: Program, *, compile_options=None, **kwargs) -> Optional[R if job.status == "failed": message = ( "The remote job %s failed due to an internal " - "server error. Please try again. (%s)" % (job.id, job.meta) + "server error. Please try again. %s" % (job.id, job.meta) ) self.log.error(message) From 8a87a98e1264e731549b8e2a78f8cf3d24d917d8 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Fri, 17 Apr 2020 15:26:00 -0400 Subject: [PATCH 03/12] Add meta attr to Job, populate on refresh --- strawberryfields/api/connection.py | 1 + strawberryfields/api/job.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/strawberryfields/api/connection.py b/strawberryfields/api/connection.py index d1b5cd5eb..e2a3ded07 100644 --- a/strawberryfields/api/connection.py +++ b/strawberryfields/api/connection.py @@ -193,6 +193,7 @@ def get_job(self, job_id: str) -> Job: id_=response.json()["id"], status=JobStatus(response.json()["status"]), connection=self, + meta=response.json()["meta"], ) raise RequestFailedError( "Failed to get job: {}".format(self._format_error_message(response)) diff --git a/strawberryfields/api/job.py b/strawberryfields/api/job.py index ef1a063e9..f7c7d802d 100644 --- a/strawberryfields/api/job.py +++ b/strawberryfields/api/job.py @@ -80,6 +80,7 @@ def __init__(self, id_: str, status: JobStatus, connection): self._status = status self._connection = connection self._result = None + self._meta = None self.log = create_logger(__name__) @@ -119,6 +120,15 @@ def result(self) -> Result: ) return self._result + @property + def meta(self) -> dict: + """Returns a dictionary of meta information on job execution. + + Returns: + dict[str, str] + """ + return self._meta + def refresh(self): """Refreshes the status of an open or queued job, along with the job result if the job is newly completed. @@ -126,7 +136,9 @@ def refresh(self): if self._status.is_final: self.log.warning("A %s job cannot be refreshed", self._status.value) return - self._status = JobStatus(self._connection.get_job_status(self.id)) + job_info = self._connection.get_job(self.id) + self._status = JobStatus(job_info.status) + self._meta = JobStatus(job_info.meta) if self._status == JobStatus.COMPLETED: self._result = self._connection.get_job_result(self.id) From c83bb862a98909fec5bb016b359f6cf7967dfba2 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Fri, 17 Apr 2020 15:36:37 -0400 Subject: [PATCH 04/12] Update Job constructor and docstrings --- strawberryfields/api/job.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/strawberryfields/api/job.py b/strawberryfields/api/job.py index f7c7d802d..dea5b1899 100644 --- a/strawberryfields/api/job.py +++ b/strawberryfields/api/job.py @@ -73,14 +73,15 @@ class Job: status (strawberryfields.api.JobStatus): the job status connection (strawberryfields.api.Connection): the connection over which the job is managed + meta (dict[str, str]): auxiliary information related to job execution """ - def __init__(self, id_: str, status: JobStatus, connection): + def __init__(self, id_: str, status: JobStatus, meta: dict, connection): self._id = id_ self._status = status + self._meta = meta self._connection = connection self._result = None - self._meta = None self.log = create_logger(__name__) @@ -122,7 +123,8 @@ def result(self) -> Result: @property def meta(self) -> dict: - """Returns a dictionary of meta information on job execution. + """Returns a dictionary of auxiliary information on job execution, such as error + details. Returns: dict[str, str] @@ -130,7 +132,7 @@ def meta(self) -> dict: return self._meta def refresh(self): - """Refreshes the status of an open or queued job, + """Refreshes the status and meta information of an open or queued job, along with the job result if the job is newly completed. """ if self._status.is_final: From 535d2edb286d40df438a2ab9ba7159eb7142ebce Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Fri, 17 Apr 2020 15:59:05 -0400 Subject: [PATCH 05/12] Update tests --- strawberryfields/api/job.py | 4 ++-- tests/api/test_connection.py | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/strawberryfields/api/job.py b/strawberryfields/api/job.py index dea5b1899..5780081be 100644 --- a/strawberryfields/api/job.py +++ b/strawberryfields/api/job.py @@ -76,12 +76,12 @@ class Job: meta (dict[str, str]): auxiliary information related to job execution """ - def __init__(self, id_: str, status: JobStatus, meta: dict, connection): + def __init__(self, id_: str, status: JobStatus, connection, meta: dict = None): self._id = id_ self._status = status - self._meta = meta self._connection = connection self._result = None + self._meta = meta if meta is not None else {} self.log = create_logger(__name__) diff --git a/tests/api/test_connection.py b/tests/api/test_connection.py index bfc531a07..3be3b2d6b 100644 --- a/tests/api/test_connection.py +++ b/tests/api/test_connection.py @@ -132,16 +132,19 @@ def test_get_all_jobs_error(self, connection, monkeypatch): def test_get_job(self, connection, monkeypatch): """Tests a successful job request.""" - id_, status = "123", JobStatus.COMPLETED + id_, status, meta = "123", JobStatus.COMPLETED, {"abc": "def"} monkeypatch.setattr( - requests, "get", mock_return(MockResponse(200, {"id": id_, "status": status.value})), + requests, + "get", + mock_return(MockResponse(200, {"id": id_, "status": status.value, "meta": meta})), ) job = connection.get_job(id_) assert job.id == id_ assert job.status == status.value + assert job.meta == meta def test_get_job_error(self, connection, monkeypatch): """Tests a failed job request.""" @@ -155,7 +158,9 @@ def test_get_job_status(self, connection, monkeypatch): id_, status = "123", JobStatus.COMPLETED monkeypatch.setattr( - requests, "get", mock_return(MockResponse(200, {"id": id_, "status": status.value})), + requests, + "get", + mock_return(MockResponse(200, {"id": id_, "status": status.value, "meta": {}})), ) assert connection.get_job_status(id_) == status.value @@ -238,6 +243,7 @@ def test_ping_failure(self, connection, monkeypatch): assert not connection.ping() + class TestConnectionIntegration: """Integration tests for using instances of the Connection.""" From 5339d0602f69b179a639e9e8bc9f84c0284cc3a7 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Fri, 17 Apr 2020 16:28:32 -0400 Subject: [PATCH 06/12] Update remote engine tests --- strawberryfields/api/job.py | 8 ++++---- tests/api/test_remote_engine.py | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/strawberryfields/api/job.py b/strawberryfields/api/job.py index 5780081be..eb3121746 100644 --- a/strawberryfields/api/job.py +++ b/strawberryfields/api/job.py @@ -73,7 +73,7 @@ class Job: status (strawberryfields.api.JobStatus): the job status connection (strawberryfields.api.Connection): the connection over which the job is managed - meta (dict[str, str]): auxiliary information related to job execution + meta (dict[str, str]): metadata related to job execution """ def __init__(self, id_: str, status: JobStatus, connection, meta: dict = None): @@ -123,7 +123,7 @@ def result(self) -> Result: @property def meta(self) -> dict: - """Returns a dictionary of auxiliary information on job execution, such as error + """Returns a dictionary of metadata on job execution, such as error details. Returns: @@ -132,7 +132,7 @@ def meta(self) -> dict: return self._meta def refresh(self): - """Refreshes the status and meta information of an open or queued job, + """Refreshes the status and metadata of an open or queued job, along with the job result if the job is newly completed. """ if self._status.is_final: @@ -140,7 +140,7 @@ def refresh(self): return job_info = self._connection.get_job(self.id) self._status = JobStatus(job_info.status) - self._meta = JobStatus(job_info.meta) + self._meta = job_info.meta if self._status == JobStatus.COMPLETED: self._result = self._connection.get_job_result(self.id) diff --git a/tests/api/test_remote_engine.py b/tests/api/test_remote_engine.py index 396cbef8a..f45b72646 100644 --- a/tests/api/test_remote_engine.py +++ b/tests/api/test_remote_engine.py @@ -35,16 +35,17 @@ class MockServer: def __init__(self): self.request_count = 0 - def get_job_status(self, _id): + def get_job(self, _id): """Returns a 'queued' job status until the number of requests exceeds a defined threshold, beyond which a 'complete' job status is returned. """ self.request_count += 1 - return ( + status = ( JobStatus.COMPLETED if self.request_count >= self.REQUESTS_BEFORE_COMPLETED else JobStatus.QUEUED ) + return Job(id_="123", status=status, connection=None) @pytest.fixture @@ -56,7 +57,7 @@ def job_to_complete(connection, monkeypatch): mock_return(Job(id_="123", status=JobStatus.OPEN, connection=connection)), ) server = MockServer() - monkeypatch.setattr(Connection, "get_job_status", server.get_job_status) + monkeypatch.setattr(Connection, "get_job", server.get_job) monkeypatch.setattr( Connection, "get_job_result", From 71bee787c9767a46545454401508ddd1866686d7 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Mon, 20 Apr 2020 09:23:41 -0400 Subject: [PATCH 07/12] Use new string formatting for error message --- strawberryfields/engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/strawberryfields/engine.py b/strawberryfields/engine.py index 0228b257a..226afaf11 100644 --- a/strawberryfields/engine.py +++ b/strawberryfields/engine.py @@ -547,8 +547,8 @@ def run(self, program: Program, *, compile_options=None, **kwargs) -> Optional[R if job.status == "failed": message = ( - "The remote job %s failed due to an internal " - "server error. Please try again. %s" % (job.id, job.meta) + "The remote job {} failed due to an internal " + "server error. Please try again. {}".format(job.id, job.meta) ) self.log.error(message) From 076d7b7607a830d5a961ccdcfac227dfc26fbd2c Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Mon, 20 Apr 2020 09:30:58 -0400 Subject: [PATCH 08/12] Log debug message with job metadata --- strawberryfields/api/job.py | 1 + 1 file changed, 1 insertion(+) diff --git a/strawberryfields/api/job.py b/strawberryfields/api/job.py index eb3121746..8bcde848e 100644 --- a/strawberryfields/api/job.py +++ b/strawberryfields/api/job.py @@ -141,6 +141,7 @@ def refresh(self): job_info = self._connection.get_job(self.id) self._status = JobStatus(job_info.status) self._meta = job_info.meta + self.log.debug("Job {} metadata: {}".format(self.id, job_info.meta)) if self._status == JobStatus.COMPLETED: self._result = self._connection.get_job_result(self.id) From bb926f611ef918139f4ef084141d5177f01b87d7 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Mon, 20 Apr 2020 12:53:04 -0400 Subject: [PATCH 09/12] Update changelog --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 464ea3c3c..a0ed19242 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -31,6 +31,9 @@

Improvements

+* Add details to the error message for failed remote jobs. + [(#370)](https://github.com/XanaduAI/strawberryfields/pull/370) +

Bug fixes

Contributors

From f33a17c2afc1c0d888d1479d43a35bf4d3eb6a52 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Mon, 20 Apr 2020 14:55:18 -0400 Subject: [PATCH 10/12] Update strawberryfields/api/job.py Co-Authored-By: antalszava --- strawberryfields/api/job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strawberryfields/api/job.py b/strawberryfields/api/job.py index 8bcde848e..95b9ff791 100644 --- a/strawberryfields/api/job.py +++ b/strawberryfields/api/job.py @@ -141,7 +141,7 @@ def refresh(self): job_info = self._connection.get_job(self.id) self._status = JobStatus(job_info.status) self._meta = job_info.meta - self.log.debug("Job {} metadata: {}".format(self.id, job_info.meta)) + self.log.debug("Job %s metadata: %s", self.id, job_info.meta) if self._status == JobStatus.COMPLETED: self._result = self._connection.get_job_result(self.id) From 899229e13fef50340539904087c2f0135300637d Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Mon, 20 Apr 2020 15:01:53 -0400 Subject: [PATCH 11/12] Add check for meta attr in async job test --- tests/api/test_remote_engine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/api/test_remote_engine.py b/tests/api/test_remote_engine.py index f45b72646..e7068b060 100644 --- a/tests/api/test_remote_engine.py +++ b/tests/api/test_remote_engine.py @@ -45,7 +45,7 @@ def get_job(self, _id): if self.request_count >= self.REQUESTS_BEFORE_COMPLETED else JobStatus.QUEUED ) - return Job(id_="123", status=status, connection=None) + return Job(id_="123", status=status, connection=None, meta={"foo": "bar"}) @pytest.fixture @@ -91,6 +91,7 @@ def test_run_async(self, connection, prog, job_to_complete): job.refresh() assert job.status == JobStatus.COMPLETED.value + assert job.meta == {"foo": "bar"} assert np.array_equal(job.result.samples, np.array([[1, 2], [3, 4]])) with pytest.raises( From 4c81ff259998fa745d704f0189c1f0dacf493caa Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Mon, 20 Apr 2020 16:06:01 -0400 Subject: [PATCH 12/12] Update strawberryfields/api/job.py Co-Authored-By: Theodor --- strawberryfields/api/job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strawberryfields/api/job.py b/strawberryfields/api/job.py index 95b9ff791..672130697 100644 --- a/strawberryfields/api/job.py +++ b/strawberryfields/api/job.py @@ -81,7 +81,7 @@ def __init__(self, id_: str, status: JobStatus, connection, meta: dict = None): self._status = status self._connection = connection self._result = None - self._meta = meta if meta is not None else {} + self._meta = meta or {} self.log = create_logger(__name__)