I am currently trying to replace a whole class Instruction
from an external module with my own implementation NamedRoutine
. I want the external module to use my re-definition instead of the original class Instruction
.
In order to have the best compatibility possible, and because I don't want to re-type the Instruction
class, the redefined class inherits from Instruction
. The NamedRoutine
implementation is:
from qiskit.circuit.instruction import Instruction
from ._interfaces import interfaces
class NamedRoutine(Instruction, interfaces.NamedRoutine):
def __init__(self, name: str, num_qubits: int, num_clbits: int, params):
super().__init__(
name=name, num_qubits=num_qubits, num_clbits=num_clbits, params=params
)
self.name = name
@staticmethod
def from_Routine(rout: Instruction) -> "NamedRoutine":
named_routine = NamedRoutine(
rout.name, rout.num_qubits, rout.num_clbits, rout.params
)
named_routine.definition = rout.definition
return named_routine
@staticmethod
def from_Routine_and_name(rout: Instruction, name: str) -> "NamedRoutine":
named_routine = NamedRoutine(
name, rout.num_qubits, rout.num_clbits, rout.params
)
named_routine.definition = rout.definition
return named_routine
def inverse(self) -> "NamedRoutine":
return NamedRoutine.from_Routine_and_name(
super().inverse(), name="D-" + self.name
)
As you can see, there is no compatibility issue between the 2 classes. The NamedRoutine
implementation just ensure that a proper name is set, adds 2 static methods and overloads one method of Instruction
to change the instance name
attribute accordingly.
In order to replace completely the definition of qiskit.circuit.instruction.Instruction
by my NamedRoutine
implementation, I tried to call the following function before any qiskit
-related code is imported:
def _wrap_instruction_class():
import qiskit.circuit.instruction
from .NamedRoutine import NamedRoutine
setattr(qiskit.circuit.instruction, "Instruction", NamedRoutine)
setattr(qiskit.circuit, "Instruction", NamedRoutine)
Note: Instruction
is imported in the __init__.py
file of qiskit.circuit
.
This method nearly works as I am successfully replacing the definitions of Instruction
by my own implementation.
The problem I am still facing is the following: when importing qiskit.circuit.instruction
, the __init__.py
files of the qiskit
and qiskit.circuit
modules are executed, and load a ton of methods/classes with the original definition of the Instruction
method (as it is still not replaced).
The number of methods/functions/classes using this Instruction
class being quite huge, I don't want to track them one by one. Moreover, this solution would require me to check after each update of the qiskit
library if one more routine/function/class need to be "injected".
I also searched for a solution "unimporting" everything from the qiskit
library except the Instruction
class, and then re-importing all the relevant parts once the Instruction
class has been modified, but it appears that unimporting is not possible in Python.
One possible solution would be to recursively import all the packages/modules of the qiskit
library and replace the symbol Instruction
with my definition if it is defined in the module, but this would require to import all the modules from qiskit
. My software is not really constrained by runtime, but this takes approximately 4 seconds on my laptop with a recent SSD and a rather clean (low number of packages) virtual environment, and it may take a lot more depending on the packages installed on the machine.
Do any of you have another solution, possibly more efficient than iterating over all the modules to find the modules in qiskit where the Instruction
symbol is defined and replace it?