Skip to content

Conversation

@yaelbh
Copy link
Collaborator

@yaelbh yaelbh commented Dec 8, 2025

Summary

Part of #2479.
Tests for the functions in the file qiskit_ibm_runtime/noise_learner_v3/noise_learner_v3.py.

Details and comments

@yaelbh yaelbh added the executor-preview Issues related to the `executor_preview` branch label Dec 8, 2025
@yaelbh yaelbh marked this pull request as draft December 8, 2025 08:59
Comment on lines 31 to 32
assert noise_learner._backend == backend
assert noise_learner._service == service
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making these properties public. Do the other primitives do that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are private for the other primitives.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of a reason for them to be private, so I would expose them as properties (obviously without setters). Accessing private attributes is something that we should avoid in every case

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do it. Anyway in a test, when we want to verify that the internals of a class were properly initialized, I think it does make sense to query private variables. I have the same story also in #2501.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was already a backend function, not a property. It's better as a property but I don't want to cause a breaking change. In 4de1380 I wrote session and service as properties, maybe change them to functions too, just for uniformity with backend?

@yaelbh yaelbh requested a review from SamFerracin December 9, 2025 10:37
@yaelbh yaelbh marked this pull request as ready for review December 9, 2025 12:13
raise ValueError(
"A backend or session/batch must be specified, or a session/batch must be open."
)
self._mode, self._service, self._backend = _get_mode_service_backend(mode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the part above redundant, because_get_mode_service_backend just undoes what was done above?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The part above was some copying of the content of _get_mode_service_backend, with some editing, that introduced bugs. Some cases were addressed (correctly or incorrectly) by the part above, without ever reaching the call to _get_mode_service_backend. Other cases did reach the call, and went through the same process again inside the function.

if configuration and not is_simulator(self._backend):
validate_options(self.options, configuration())
target = getattr(self._backend, "target", None)
if target and not is_simulator(self._backend):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what happens if self._backend is a simulator, I would expect it to raise somewhere (init or run? 🤷). The truth is that we never supported simulators for NoiseLearner, and the same applies to NoiseLearnerV3.

If this is indeed the case, I would prefer to add a check to the init along the lines of:

if is_simulator(self._backend):
    raise ValueError("Simulator backend is not supported.")

And then here:

  • We would not need to check is_simulator anymore
  • We would need to raise ValueError if target or configuration is None, because real backends do have a target and a config

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • We already raise, in init, if we fall on the QiskitRuntimeLocalService, perhaps it covers the case of a simulator?
  • If real backends always have a target and a config then why check it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it can be a simulator at this point, so I removed the check in 4b98826. I also think the check if target and config are None is redundant, but why not. We can also revert and think about all this in a separate issue.

Comment on lines 31 to 32
assert noise_learner._backend == backend
assert noise_learner._service == service
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of a reason for them to be private, so I would expose them as properties (obviously without setters). Accessing private attributes is something that we should avoid in every case

Comment on lines 39 to 41
session = get_mocked_session(get_mocked_backend(backend_name))
session.reset_mock()
session.service.reset_mock()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why do we need to reset (twice) something that we just initialized. We should check (in another issue) if we can improve this mock

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied it from the primitives v2 tests. We should check what happens in this regard when tests run in parallel.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed I don't see a reason for any of the calls to reset_mock in test_noise_learner_v3.py, and for most of the calls in test_ibm_primitives_v2.py. To be on the safe side, as you say, we'll face it in another issue.

self.assertEqual(noise_learner._backend, backend)
self.assertEqual(noise_learner._service, service)

def test_run_of_session_is_selected(self):
Copy link
Collaborator

@SamFerracin SamFerracin Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this test and in the next one you are manually monkey-patching by overwriting service._run. This is not good practice as it can have undesirable side effects, such as leakage (the manual change persists beyond the single test case that made it).

Please use unittest.mock, which takes care of the cleanup. There are some examples in other files

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how a leakage can occur. The mocked session is local only to this test. But I agree that the good practice is do something like done in c47364c. By the way note that we override session data members inside get_mocked_session.

@yaelbh yaelbh requested a review from SamFerracin December 10, 2025 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

executor-preview Issues related to the `executor_preview` branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants