Repository: Qiskit/qiskit

Issue:
Access a job's payload through `job.qobj()`
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues to confirm this idea does not exist. -->

### What is the expected enhancement?
One often wants to know the `job.qobj()` associated with a job as well (right now you can only get `job.result()` for previous jobs).



Discussion:

Resolving patch:
diff --git a/qiskit/providers/builtinsimulators/simulatorsjob.py b/qiskit/providers/builtinsimulators/simulatorsjob.py
--- a/qiskit/providers/builtinsimulators/simulatorsjob.py
+++ b/qiskit/providers/builtinsimulators/simulatorsjob.py
@@ -124,3 +124,11 @@ def status(self):
     def backend(self):
         """Return the instance of the backend used for this job."""
         return self._backend
+
+    def qobj(self):
+        """Return the Qobj submitted for this job.
+
+        Returns:
+            Qobj: the Qobj submitted for this job.
+        """
+        return self._qobj
diff --git a/qiskit/providers/ibmq/ibmqjob.py b/qiskit/providers/ibmq/ibmqjob.py
--- a/qiskit/providers/ibmq/ibmqjob.py
+++ b/qiskit/providers/ibmq/ibmqjob.py
@@ -11,6 +11,7 @@
 IBM Q Experience.
 """
 
+import warnings
 from concurrent import futures
 import time
 import logging
@@ -20,7 +21,7 @@
 import datetime
 import numpy
 
-from qiskit.qobj import qobj_to_dict
+from qiskit.qobj import qobj_to_dict, Qobj
 from qiskit.transpiler import transpile_dag
 from qiskit.providers import BaseJob, JobError, JobTimeoutError
 from qiskit.providers.jobstatus import JobStatus, JOB_FINAL_STATES
@@ -208,6 +209,8 @@ def _wait_for_result(self, timeout=None, wait=5):
 
         try:
             job_response = self._wait_for_job(timeout=timeout, wait=wait)
+            if not self._qobj_payload:
+                self._qobj_payload = job_response.get('qObject', {})
         except ApiError as api_err:
             raise JobError(str(api_err))
 
@@ -420,6 +423,21 @@ def _wait_for_submission(self, timeout=60):
                 self._api_error_msg = str(submit_info['error'])
                 raise JobError(str(submit_info['error']))
 
+    def qobj(self):
+        """Return the Qobj submitted for this job.
+
+        Note that this method might involve querying the API for results if the
+        Job has been created in a previous Qiskit session.
+
+        Returns:
+            Qobj: the Qobj submitted for this job.
+        """
+        if not self._qobj_payload:
+            # Populate self._qobj_payload by retrieving the results.
+            self._wait_for_result()
+
+        return Qobj(**self._qobj_payload)
+
 
 class IBMQJobPreQobj(IBMQJob):
     """
@@ -505,6 +523,11 @@ def _result_from_job_response(self, job_response):
 
         return result_from_old_style_dict(ret)
 
+    def qobj(self):
+        """Return the Qobj submitted for this job."""
+        warnings.warn('This job has not been submitted using Qobj.')
+        return None
+
 
 def _reorder_bits(job_data):
     """Temporary fix for ibmq backends.


Test patch:
diff --git a/test/python/ibmq/test_ibmqjob.py b/test/python/ibmq/test_ibmqjob.py
--- a/test/python/ibmq/test_ibmqjob.py
+++ b/test/python/ibmq/test_ibmqjob.py
@@ -259,8 +259,12 @@ def test_retrieve_job(self, qe_token, qe_url):
         job = backend.run(qobj)
 
         rjob = backend.retrieve_job(job.job_id())
-        self.assertTrue(job.job_id() == rjob.job_id())
-        self.assertTrue(job.result().get_counts() == rjob.result().get_counts())
+        self.assertEqual(job.job_id(), rjob.job_id())
+        self.assertEqual(job.result().get_counts(), rjob.result().get_counts())
+        if getattr(backend.configuration(), 'allow_q_object'):
+            self.assertEqual(job.qobj().as_dict(), qobj.as_dict())
+        else:
+            self.assertEqual(job.qobj(), None)
 
     @requires_qe_access
     def test_retrieve_job_error(self, qe_token, qe_url):
diff --git a/test/python/simulators/test_terra_simulators.py b/test/python/simulators/test_terra_simulators.py
--- a/test/python/simulators/test_terra_simulators.py
+++ b/test/python/simulators/test_terra_simulators.py
@@ -45,3 +45,13 @@ def test_qobj_headers_in_result(self):
                     self.assertEqual(result.header.to_dict(), custom_qobj_header)
                     self.assertEqual(result.results[0].header.some_field,
                                      'extra info')
+
+    def test_job_qobj(self):
+        """Test job.qobj()."""
+        for provider in (BasicAer, LegacySimulators):
+            for backend in provider.backends():
+                with self.subTest(provider=provider, backend=backend):
+                    qobj = compile(self.qc1, backend)
+
+                    job = backend.run(qobj)
+                    self.assertEqual(job.qobj(), qobj)