# Buggy code
def __str__(self):
    s = ""
    if self.type == "oper" or self.type == "super":
        s += (
            "Quantum object: "
            + "dims = "
            + str(self.dims)
            + ", shape = "
            + str(self.shape)
            + ", type = "
            + self.type
            + ", isherm = "
            + str(self._isherm)
            + (
                ", superrep = {0.superrep}".format(self)
                if self.type == "super" and self.superrep != "super"
                else ""
            )
            + "\n"
        )
    else:
        s += (
            "Quantum object: "
            + "dims = "
            + str(self.dims)
            + ", shape = "
            + str(self.shape)
            + ", type = "
            + self.type
            + "\n"
        )
    s += "Qobj data =\n"

    if self.shape[0] > 10000 or self.shape[1] > 10000:
        # if the system is huge, don't attempt to convert to a
        # dense matrix and then to string, because it is pointless
        # and is likely going to produce memory errors. Instead print the
        # sparse data string representation
        s += str(self.data)

    elif all(np.imag(self.data.data) == 0):
        s += str(np.real(self.full()))

    else:
        s += str(self.full())

    return s


# Traceback (TypeError)
rho_psi = operator_to_vector(Qobj(np.diag(np.array([0.9, 0.1], dtype=complex))))>>> E_psi = rho_psi.dag()
S = to_super(sigmax())
(E_psi * S) * rho_psi
Traceback (most recent call last):
File "<ipython-input-22-90cbfac2a43e>", line 1, in <module>
(E_psi * S) * rho_psi
File "qutip/qobj.py", line 416, in __mul__
raise TypeError("Incompatible Qobj shapes")
TypeError: Incompatible Qobj shapes

E_psi * (S * rho_psi)
Quantum object: dims = [[1], [1]], shape = [1, 1], type = oper, isherm = True
Qobj data =
[[ 0.18]]
E_psi
Quantum object: dims = [[1], [[2], [2]]], shape = [1, 4], type = bra
Qobj data =
[[ 0.9  0.   0.   0.1]]
rho_psi
Quantum object: dims = [[[2], [2]], [1]], shape = [4, 1], type = operator-vector
Qobj data =
[[ 0.9]
[ 0. ]
[ 0. ]
[ 0.1]]
S
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = [4, 4], type = super, isherm = True
Qobj data =
[[ 0.  0.  0.  1.]
[ 0.  0.  1.  0.]
[ 0.  1.  0.  0.]
[ 1.  0.  0.  0.]]

# Fixed code
def __str__(self):
    s = ""
    if self.type in ["oper", "super"]:
        s += (
            "Quantum object: "
            + "dims = "
            + str(self.dims)
            + ", shape = "
            + str(self.shape)
            + ", type = "
            + self.type
            + ", isherm = "
            + str(self._isherm)
            + (
                ", superrep = {0.superrep}".format(self)
                if self.type == "super" and self.superrep != "super"
                else ""
            )
            + "\n"
        )
    else:
        s += (
            "Quantum object: "
            + "dims = "
            + str(self.dims)
            + ", shape = "
            + str(self.shape)
            + ", type = "
            + self.type
            + "\n"
        )
    s += "Qobj data =\n"

    if self.shape[0] > 10000 or self.shape[1] > 10000:
        # if the system is huge, don't attempt to convert to a
        # dense matrix and then to string, because it is pointless
        # and is likely going to produce memory errors. Instead print the
        # sparse data string representation
        s += str(self.data)

    elif all(np.imag(self.data.data) == 0):
        s += str(np.real(self.full()))

    else:
        s += str(self.full())

    return s