diff --git a/qiskit_ibm/api/clients/runtime.py b/qiskit_ibm/api/clients/runtime.py index 5cc4df6b5..abe096c30 100644 --- a/qiskit_ibm/api/clients/runtime.py +++ b/qiskit_ibm/api/clients/runtime.py @@ -39,17 +39,17 @@ def __init__( **credentials.connection_parameters()) self.api = Runtime(self._session) - def list_programs(self, limit: int = None, skip: int = None) -> Dict[str, Any]: + def list_programs(self, name: str = "", limit: int = None, skip: int = None) -> Dict[str, Any]: """Return a list of runtime programs. Args: limit: The number of programs to return. skip: The number of programs to skip. - + name: Name of the program. Returns: A list of runtime programs. """ - return self.api.list_programs(limit, skip) + return self.api.list_programs(name, limit, skip) def program_create( self, diff --git a/qiskit_ibm/api/rest/runtime.py b/qiskit_ibm/api/rest/runtime.py index e44265c96..ff54771b9 100644 --- a/qiskit_ibm/api/rest/runtime.py +++ b/qiskit_ibm/api/rest/runtime.py @@ -55,18 +55,20 @@ def program_job(self, job_id: str) -> 'ProgramJob': """ return ProgramJob(self.session, job_id) - def list_programs(self, limit: int = None, skip: int = None) -> Dict[str, Any]: + def list_programs(self, name: str = "", limit: int = None, skip: int = None) -> Dict[str, Any]: """Return a list of runtime programs. Args: limit: The number of programs to return. skip: The number of programs to skip. - + name: Name of the program. Returns: A list of runtime programs. """ url = self.get_url('programs') - payload: Dict[str, int] = {} + payload: Dict[str, Union[int, str]] = {} + if name: + payload['name'] = name if limit: payload['limit'] = limit if skip: diff --git a/qiskit_ibm/runtime/ibm_runtime_service.py b/qiskit_ibm/runtime/ibm_runtime_service.py index a131b4298..d13c448cd 100644 --- a/qiskit_ibm/runtime/ibm_runtime_service.py +++ b/qiskit_ibm/runtime/ibm_runtime_service.py @@ -108,18 +108,19 @@ def __init__(self, provider: 'ibm_provider.IBMProvider') -> None: self._programs = {} # type: Dict def pprint_programs(self, refresh: bool = False, detailed: bool = False, - limit: int = 20, skip: int = 0) -> None: + name: Optional[str] = "", limit: int = 20, skip: int = 0) -> None: """Pretty print information about available runtime programs. Args: refresh: If ``True``, re-query the server for the programs. Otherwise return the cached value. detailed: If ``True`` print all details about available runtime programs. + name: Only retrieve programs with the exact program name given. limit: The number of programs returned at a time. Default and maximum value of 20. skip: The number of programs to skip. """ - programs = self.programs(refresh, limit, skip) + programs = self.programs(refresh, name, limit, skip) for prog in programs: print("="*50) if detailed: @@ -129,7 +130,7 @@ def pprint_programs(self, refresh: bool = False, detailed: bool = False, print(f" Name: {prog.name}") print(f" Description: {prog.description}") - def programs(self, refresh: bool = False, + def programs(self, refresh: bool = False, name: Optional[str] = "", limit: int = 20, skip: int = 0) -> List[RuntimeProgram]: """Return available runtime programs. @@ -138,6 +139,7 @@ def programs(self, refresh: bool = False, Args: refresh: If ``True``, re-query the server for the programs. Otherwise return the cached value. + name: Only retrieve programs with the exact program name given. limit: The number of programs returned at a time. ``None`` means no limit. skip: The number of programs to skip. @@ -146,12 +148,21 @@ def programs(self, refresh: bool = False, """ if skip is None: skip = 0 + if name: + matched_programs = [] + for prog in list(self._programs.values())[skip:limit+skip]: + if prog.name == name: + matched_programs.append(prog) + if matched_programs: + return matched_programs + refresh = True if not self._programs or refresh: self._programs = {} current_page_limit = 20 offset = 0 while True: - response = self._api_client.list_programs(limit=current_page_limit, skip=offset) + response = self._api_client.list_programs(name=name, limit=current_page_limit, + skip=offset) program_page = response.get("programs", []) # count is the total number of programs that would be returned if # there was no limit or skip diff --git a/releasenotes/notes/query-program-name-823e8e7cfef44f50.yaml b/releasenotes/notes/query-program-name-823e8e7cfef44f50.yaml new file mode 100644 index 000000000..5c4a475a6 --- /dev/null +++ b/releasenotes/notes/query-program-name-823e8e7cfef44f50.yaml @@ -0,0 +1,8 @@ +--- +upgrade: + - | + The ``name`` parameter has been added to + :meth:`qiskit_ibm.runtime.IBMRuntimeService.programs` and + :meth:`qiskit_ibm.runtime.IBMRuntimeService.pprint_programs` + which can be used to filter by a specific program name. The + ``name`` given must be an exact match with an actual program name. \ No newline at end of file diff --git a/test/ibm/runtime/fake_runtime_client.py b/test/ibm/runtime/fake_runtime_client.py index a8b6643fd..efdc4d05d 100644 --- a/test/ibm/runtime/fake_runtime_client.py +++ b/test/ibm/runtime/fake_runtime_client.py @@ -242,12 +242,15 @@ def set_final_status(self, final_status): """Set job status to passed in final status instantly.""" self._final_status = final_status - def list_programs(self, limit, skip): + def list_programs(self, name, limit, skip): """List all programs.""" programs = [] for prog in self._programs.values(): - programs.append(prog.to_dict()) - return {"programs": programs[skip:limit+skip], "count": len(self._programs)} + if not name: + programs.append(prog.to_dict()) + if name == prog.to_dict()['name']: + programs.append(prog.to_dict()) + return {"programs": programs[skip:limit+skip], "count": len(programs)} def program_create(self, program_data, name, description, max_execution_time, spec=None, is_public=False): diff --git a/test/ibm/runtime/test_runtime.py b/test/ibm/runtime/test_runtime.py index 1964ddbd1..0addf0e40 100644 --- a/test/ibm/runtime/test_runtime.py +++ b/test/ibm/runtime/test_runtime.py @@ -302,6 +302,16 @@ def test_list_programs(self): all_ids = [prog.program_id for prog in programs] self.assertIn(program_id, all_ids) + def test_filter_programs_with_program_name(self): + """Test filter programs with the program name""" + program_id = self._upload_program(name="qiskit-test-sample") + programs = self.runtime.programs(name="qiskit-test-sample") + all_ids = [prog.program_id for prog in programs] + self.assertIn(program_id, all_ids) + programs = self.runtime.programs(name="qiskit-test") + all_ids = [prog.program_id for prog in programs] + self.assertNotIn(program_id, all_ids) + def test_list_programs_with_limit_skip(self): """Test listing programs with limit and skip.""" program_1 = self._upload_program() diff --git a/test/ibm/runtime/test_runtime_integration.py b/test/ibm/runtime/test_runtime_integration.py index 351186c69..126c73205 100644 --- a/test/ibm/runtime/test_runtime_integration.py +++ b/test/ibm/runtime/test_runtime_integration.py @@ -141,6 +141,16 @@ def test_list_programs(self): found = True self.assertTrue(found, f"Program {self.program_id} not found!") + def test_filter_programs_with_program_name(self): + """Test filter programs with program name.""" + program_id = self._upload_program(name="qiskit-test-sample") + programs = self.provider.runtime.programs(name="qiskit-test-sample") + all_ids = [prog.program_id for prog in programs] + self.assertIn(program_id, all_ids) + programs = self.provider.runtime.programs(name="qiskit-test") + all_ids = [prog.program_id for prog in programs] + self.assertNotIn(program_id, all_ids) + def test_list_programs_with_limit_skip(self): """Test listing programs with limit and skip.""" self._upload_program()