# Buggy code
def update_state_sqp(
    state,
    x,
    last_iteration_failed,
    objective,
    prepared_constraints,
    start_time,
    tr_radius,
    constr_penalty,
    cg_info,
):
    state.niter += 1
    state.nfev = objective.nfev
    state.njev = objective.ngev
    state.nhev = objective.nhev
    state.constr_nfev = [
        c.fun.nfev if isinstance(c.fun, VectorFunction) else 0
        for c in prepared_constraints
    ]
    state.constr_njev = [
        c.fun.njev if isinstance(c.fun, VectorFunction) else 0
        for c in prepared_constraints
    ]
    state.constr_nhev = [
        c.fun.nhev if isinstance(c.fun, VectorFunction) else 0
        for c in prepared_constraints
    ]

    if not last_iteration_failed:
        state.x = x
        state.fun = objective.f
        state.grad = objective.g
        state.v = [c.fun.v for c in prepared_constraints]
        state.constr = [c.fun.f for c in prepared_constraints]
        state.jac = [c.fun.J for c in prepared_constraints]
        # Compute Lagrangian Gradient
        state.lagrangian_grad = np.copy(state.grad)
        for c in prepared_constraints:
            state.lagrangian_grad += c.fun.J.T.dot(c.fun.v)
        state.optimality = np.linalg.norm(state.lagrangian_grad, np.inf)
        # Compute maximum constraint violation
        state.constr_violation = 0
        for i in range(len(prepared_constraints)):
            lb, ub = prepared_constraints[i].bounds
            c = state.constr[i]
            state.constr_violation = np.max(
                [state.constr_violation, np.max(lb - c), np.max(c - ub)]
            )

    state.execution_time = time.time() - start_time
    state.tr_radius = tr_radius
    state.constr_penalty = constr_penalty
    state.cg_niter += cg_info["niter"]
    state.cg_stop_cond = cg_info["stop_cond"]

    return state


# Traceback (AttributeError)
['cg_niter', 'cg_stop_cond', 'constr', 'constr_nfev', 'constr_nhev',
'constr_njev', 'constr_penalty', 'constr_violation', 'execution_time',
'fun', 'grad', 'jac', 'lagrangian_grad', 'message', 'method', 'nfev',
'nhev', 'niter', 'njev', 'optimality', 'status', 'tr_radius', 'v', 'x']
Traceback (most recent call last):
File "<ipython-input-13-492cf8a99d03>", line 3, in <module>
assert sol.success
File "/home/pauli/.local/lib/python3.6/site-packages/scipy/optimize/optimize.py", line 116, in __getattr__
raise AttributeError(name)
AttributeError: success

# Fixed code
def update_state_sqp(
    state,
    x,
    last_iteration_failed,
    objective,
    prepared_constraints,
    start_time,
    tr_radius,
    constr_penalty,
    cg_info,
):
    state.nit += 1
    state.nfev = objective.nfev
    state.njev = objective.ngev
    state.nhev = objective.nhev
    state.constr_nfev = [
        c.fun.nfev if isinstance(c.fun, VectorFunction) else 0
        for c in prepared_constraints
    ]
    state.constr_njev = [
        c.fun.njev if isinstance(c.fun, VectorFunction) else 0
        for c in prepared_constraints
    ]
    state.constr_nhev = [
        c.fun.nhev if isinstance(c.fun, VectorFunction) else 0
        for c in prepared_constraints
    ]

    if not last_iteration_failed:
        state.x = x
        state.fun = objective.f
        state.grad = objective.g
        state.v = [c.fun.v for c in prepared_constraints]
        state.constr = [c.fun.f for c in prepared_constraints]
        state.jac = [c.fun.J for c in prepared_constraints]
        # Compute Lagrangian Gradient
        state.lagrangian_grad = np.copy(state.grad)
        for c in prepared_constraints:
            state.lagrangian_grad += c.fun.J.T.dot(c.fun.v)
        state.optimality = np.linalg.norm(state.lagrangian_grad, np.inf)
        # Compute maximum constraint violation
        state.constr_violation = 0
        for i in range(len(prepared_constraints)):
            lb, ub = prepared_constraints[i].bounds
            c = state.constr[i]
            state.constr_violation = np.max(
                [state.constr_violation, np.max(lb - c), np.max(c - ub)]
            )

    state.execution_time = time.time() - start_time
    state.tr_radius = tr_radius
    state.constr_penalty = constr_penalty
    state.cg_niter += cg_info["niter"]
    state.cg_stop_cond = cg_info["stop_cond"]

    return state