Skip to content

Commit

Permalink
Define custom json encoder for qobj payloads
Browse files Browse the repository at this point in the history
The qobj payload has a couple of quirks related to how qobj objects can
be constructed (and will be constructed after Qiskit/qiskit#3383
merges) that aren't handled by the default json encoder. The first is
that complex numbers are converted to the form "(real, imaginary)", and
the second is that numpy arrays are sometimes part of the payload.
Instead of relying on a layer outside of the provider coercing these
objects to the expected format this commit changes how we push qobj
payloads to the iqx api so that we run it through a json encoder that
understands how to do this. After this commit qiskit-ibmq-provider owns
it's own payload format and the generation of the expected json payload
format instead of relying on an external library to handle it for us.

Related to Qiskit#553
  • Loading branch information
mtreinish committed Feb 19, 2020
1 parent 4fa201b commit 9d845d7
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
4 changes: 3 additions & 1 deletion qiskit/providers/ibmq/api/rest/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .validation import StatusResponseSchema
from ..session import RetrySession
from ..exceptions import ApiIBMQProtocolError
from qiskit.providers.ibmq.utils import json_encoder


class Job(RestAdapterBase):
Expand Down Expand Up @@ -137,7 +138,8 @@ def put_object_storage(self, url: str, qobj_dict: Dict[str, Any]) -> str:
Returns:
text response, that will be empty if the request was successful.
"""
response = self.session.put(url, json=qobj_dict, bare=True)
data = json.dumps(qobj_dict, cls=json_encoder.IQXJsonEconder)
response = self.session.put(url, data=data, bare=True)
return response.text

def get_object_storage(self, url: str) -> Dict[str, Any]:
Expand Down
4 changes: 3 additions & 1 deletion qiskit/providers/ibmq/api/rest/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .base import RestAdapterBase
from .backend import Backend
from .job import Job
from qiskit.providers.ibmq.utils import json_encoder


class Api(RestAdapterBase):
Expand Down Expand Up @@ -140,7 +141,8 @@ def job_submit(
if job_tags:
payload['tags'] = job_tags

return self.session.post(url, json=payload).json()
data = json.dumps(payload, cls=json_encoder.IQXJsonEconder)
return self.session.post(url, data=data).json()

def submit_job_object_storage(
self,
Expand Down
33 changes: 33 additions & 0 deletions qiskit/providers/ibmq/utils/json_encoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

# pylint: disable=method-hidden

"""Custom JSON encoders."""

import json
from typing import Any


class IQXJsonEconder(json.JSONEncoder):
"""A json encoder for qobj"""

def default(self, o: Any):
# Convert numpy arrays:
if hasattr(o, 'tolist'):
return o.tolist()
# Use Qobj complex json format:
if isinstance(o, complex):
return (o.real, o.imag)
return json.JSONEncoder.default(self, o)

0 comments on commit 9d845d7

Please sign in to comment.