diff --git a/qiskit_ibm_runtime/base_runtime_job.py b/qiskit_ibm_runtime/base_runtime_job.py index f0d324028..50aedf91a 100644 --- a/qiskit_ibm_runtime/base_runtime_job.py +++ b/qiskit_ibm_runtime/base_runtime_job.py @@ -67,6 +67,7 @@ def __init__( session_id: Optional[str] = None, tags: Optional[List] = None, version: Optional[int] = None, + private: Optional[bool] = False, ) -> None: """RuntimeJob constructor. @@ -84,6 +85,7 @@ def __init__( session_id: Job ID of the first job in a runtime session. tags: Tags assigned to the job. version: Primitive version. + private: Marks job as private. """ self._backend = backend self._job_id = job_id @@ -101,6 +103,7 @@ def __init__( self._version = version self._queue_info: QueueInfo = None self._status: Union[RuntimeJobStatus, str] = None + self._private = private decoder = result_decoder or DEFAULT_DECODERS.get(program_id, None) or ResultDecoder if isinstance(decoder, Sequence): @@ -116,6 +119,11 @@ def __init__( "results streaming was removed in a previous release.", ) + @property + def private(self) -> bool: + """Returns a boolean indicating whether or not the job is private.""" + return self._private + def job_id(self) -> str: """Return a unique id identifying the job.""" return self._job_id diff --git a/qiskit_ibm_runtime/options/environment_options.py b/qiskit_ibm_runtime/options/environment_options.py index 69c26b47d..5af179d87 100644 --- a/qiskit_ibm_runtime/options/environment_options.py +++ b/qiskit_ibm_runtime/options/environment_options.py @@ -52,12 +52,12 @@ class EnvironmentOptions: Default: ``None``. """ private: Optional[bool] = False - r"""Boolean that indicates whether the job is marked as private. This is only - supported for ``ibm_quantum`` channel. When set to true, input parameters are not - returned, and the results can only be read once. After the results are read or after - a specified time after the job is completed, the results are deleted from the service. - When set to false, the input parameters and results follow the standard retention - behavior. + r"""Boolean that indicates whether the job is marked as private. When set to true, + input parameters are not returned, and the results can only be read once. + After the job is completed, input parameters are deleted from the service. + After the results are read, these are also deleted from the service. + When set to false, the input parameters and results follow the + standard retention behavior of the API. Default: False. """ diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 5a9ec434c..4980828e5 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -893,6 +893,7 @@ def _run( image=qrt_options.image, service=self, version=version, + private=qrt_options.private, ) def check_pending_jobs(self) -> None: @@ -1136,6 +1137,7 @@ def _decode_job(self, raw_data: Dict) -> Union[RuntimeJob, RuntimeJobV2]: image=raw_data.get("runtime"), session_id=raw_data.get("session_id"), tags=raw_data.get("tags"), + private=raw_data.get("private", False), ) def least_busy( diff --git a/qiskit_ibm_runtime/runtime_job_v2.py b/qiskit_ibm_runtime/runtime_job_v2.py index 25a64a17e..046d28c97 100644 --- a/qiskit_ibm_runtime/runtime_job_v2.py +++ b/qiskit_ibm_runtime/runtime_job_v2.py @@ -70,6 +70,7 @@ def __init__( session_id: Optional[str] = None, tags: Optional[List] = None, version: Optional[int] = None, + private: Optional[bool] = False, ) -> None: """RuntimeJob constructor. @@ -87,6 +88,7 @@ def __init__( session_id: Job ID of the first job in a runtime session. tags: Tags assigned to the job. version: Primitive version. + private: Marks job as private. """ BasePrimitiveJob.__init__(self, job_id=job_id) BaseRuntimeJob.__init__( @@ -104,6 +106,7 @@ def __init__( session_id=session_id, tags=tags, version=version, + private=private, ) self._status: JobStatus = "INITIALIZING" diff --git a/qiskit_ibm_runtime/runtime_options.py b/qiskit_ibm_runtime/runtime_options.py index 822fc0aa0..7dd427345 100644 --- a/qiskit_ibm_runtime/runtime_options.py +++ b/qiskit_ibm_runtime/runtime_options.py @@ -70,12 +70,12 @@ def __init__( this time limit, it is forcibly cancelled. Simulator jobs continue to use wall clock time. session_time: Length of session in seconds. - private: Boolean that indicates whether the job is marked as private. This is only - supported for ``ibm_quantum`` channel. When set to true, input parameters are not - returned, and the results can only be read once. After the results are read or after - a specified time after the job is completed, the results are deleted from the service. - When set to false, the input parameters and results follow the standard retention - behavior. + private: Boolean that indicates whether the job is marked as private. When set to true, + input parameters are not returned, and the results can only be read once. + After the job is completed, input parameters are deleted from the service. + After the results are read, these are also deleted from the service. + When set to false, the input parameters and results follow the + standard retention behavior of the API. """ self.backend = backend self.image = image diff --git a/release-notes/unreleased/2263.feat.rst b/release-notes/unreleased/2263.feat.rst new file mode 100644 index 000000000..2cfa0512f --- /dev/null +++ b/release-notes/unreleased/2263.feat.rst @@ -0,0 +1,7 @@ +The ``private`` option under :class:`EnvironmentOptions` is now supported on the +``ibm_cloud`` and ``ibm_quantum_platform`` channels (new IBM Quantum Platform). When this option +is set to ``True``, the job will be returned without params and results can only +be retrieved once. + +There is also a new :meth:`~.RuntimeJobV2.private` property that returns whether +or not a job is private. \ No newline at end of file diff --git a/test/integration/test_ibm_job_attributes.py b/test/integration/test_ibm_job_attributes.py index d47127a10..25f10baea 100644 --- a/test/integration/test_ibm_job_attributes.py +++ b/test/integration/test_ibm_job_attributes.py @@ -163,12 +163,7 @@ def test_cost_estimation(self): def test_private_option(self): """Test private option.""" - if self.dependencies.channel == "ibm_cloud": - raise SkipTest("Cloud channel does not support private jobs") - try: - backend = self.service.backend("test_eagle") - except: - raise SkipTest("test_eagle not available in this environment") + backend = self.dependencies.service.backend(self.dependencies.qpu) sampler = Sampler(mode=backend) sampler.options.environment.private = True @@ -177,3 +172,4 @@ def test_private_option(self): self.assertFalse(job.inputs) self.assertTrue(job.result()) self.assertFalse(job.result()) # private job results can only be retrieved once + self.assertTrue(job.private)