//  [python]
def _parse_pot(pot, potforactions=False, potfortorus=False):
    """Parse the potential so it can be fed to C"""
    # Figure out what's in pot
    if not isinstance(pot, list):
        pot = [pot]
    if (potforactions or potfortorus) and (
        (len(pot) == 1 and isinstance(pot[0], potential.NullPotential))
        or numpy.all([isinstance(p, potential.NullPotential) for p in pot])
    ):
        raise NotImplementedError(
            "Evaluating actions using the C backend is not supported for NullPotential instances"
        )
    # Remove NullPotentials from list of Potentials containing other potentials
    purged_pot = [p for p in pot if not isinstance(p, potential.NullPotential)]
    if len(purged_pot) > 0:
        pot = purged_pot
    # Initialize everything
    pot_type = []
    pot_args = []
    pot_tfuncs = []
    npot = len(pot)
    for p in pot:
        if isinstance(p, potential.LogarithmicHaloPotential):
            pot_type.append(0)
            if p.isNonAxi:
                pot_args.extend([p._amp, p._q, p._core2, p._1m1overb2])
            else:
                pot_args.extend([p._amp, p._q, p._core2, 2.0])  # 1m1overb2 > 1: axi
        elif isinstance(p, potential.DehnenBarPotential):
            pot_type.append(1)
            pot_args.extend(
                [p._amp * p._af, p._tform, p._tsteady, p._rb, p._omegab, p._barphi]
            )
        elif isinstance(p, potential.MiyamotoNagaiPotential):
            pot_type.append(5)
            pot_args.extend([p._amp, p._a, p._b])
        elif isinstance(p, potential.PowerSphericalPotential):
            pot_type.append(7)
            pot_args.extend([p._amp, p.alpha])
        elif isinstance(p, potential.HernquistPotential):
            pot_type.append(8)
            pot_args.extend([p._amp, p.a])
        elif isinstance(p, potential.NFWPotential):
            pot_type.append(9)
            pot_args.extend([p._amp, p.a])
        elif isinstance(p, potential.JaffePotential):
            pot_type.append(10)
            pot_args.extend([p._amp, p.a])
        elif isinstance(p, potential.DoubleExponentialDiskPotential):
            pot_type.append(11)
            pot_args.extend(
                [
                    p._amp,
                    -4.0 * numpy.pi * p._alpha * p._amp,
                    p._alpha,
                    p._beta,
                    len(p._de_j1_xs),
                ]
            )
            pot_args.extend(p._de_j0_xs)
            pot_args.extend(p._de_j1_xs)
            pot_args.extend(p._de_j0_weights)
            pot_args.extend(p._de_j1_weights)
        elif isinstance(p, potential.FlattenedPowerPotential):
            pot_type.append(12)
            pot_args.extend([p._amp, p.alpha, p.q2, p.core2])
        elif isinstance(p, potential.interpRZPotential):
            pot_type.append(13)
            pot_args.extend([len(p._rgrid), len(p._zgrid)])
            if p._logR:
                pot_args.extend([p._logrgrid[ii] for ii in range(len(p._rgrid))])
            else:
                pot_args.extend([p._rgrid[ii] for ii in range(len(p._rgrid))])
            pot_args.extend([p._zgrid[ii] for ii in range(len(p._zgrid))])
            if hasattr(p, "_potGrid_splinecoeffs"):
                pot_args.extend([x for x in p._potGrid_splinecoeffs.flatten(order="C")])
            else:  # pragma: no cover
                warnings.warn(
                    "You are attempting to use the C implementation of interpRZPotential, but have not interpolated the potential itself; if you think this is needed for what you want to do, initialize the interpRZPotential instance with interpPot=True",
                    galpyWarning,
                )
                pot_args.extend(list(numpy.ones(len(p._rgrid) * len(p._zgrid))))
            if hasattr(p, "_rforceGrid_splinecoeffs"):
                pot_args.extend(
                    [x for x in p._rforceGrid_splinecoeffs.flatten(order="C")]
                )
            else:  # pragma: no cover
                warnings.warn(
                    "You are attempting to use the C implementation of interpRZPotential, but have not interpolated the Rforce; if you think this is needed for what you want to do, initialize the interpRZPotential instance with interpRforce=True",
                    galpyWarning,
                )
                pot_args.extend(list(numpy.ones(len(p._rgrid) * len(p._zgrid))))
            if hasattr(p, "_zforceGrid_splinecoeffs"):
                pot_args.extend(
                    [x for x in p._zforceGrid_splinecoeffs.flatten(order="C")]
                )
            else:  # pragma: no cover
                warnings.warn(
                    "You are attempting to use the C implementation of interpRZPotential, but have not interpolated the zforce; if you think this is needed for what you want to do, initialize the interpRZPotential instance with interpzforce=True",
                    galpyWarning,
                )
                pot_args.extend(list(numpy.ones(len(p._rgrid) * len(p._zgrid))))
            pot_args.extend([p._amp, int(p._logR)])
        elif isinstance(p, potential.IsochronePotential):
            pot_type.append(14)
            pot_args.extend([p._amp, p.b])
        elif isinstance(p, potential.PowerSphericalPotentialwCutoff):
            pot_type.append(15)
            pot_args.extend([p._amp, p.alpha, p.rc])
        elif isinstance(p, potential.MN3ExponentialDiskPotential):
            # Three Miyamoto-Nagai disks
            npot += 2
            pot_type.extend([5, 5, 5])
            pot_args.extend(
                [
                    p._amp * p._mn3[0]._amp,
                    p._mn3[0]._a,
                    p._mn3[0]._b,
                    p._amp * p._mn3[1]._amp,
                    p._mn3[1]._a,
                    p._mn3[1]._b,
                    p._amp * p._mn3[2]._amp,
                    p._mn3[2]._a,
                    p._mn3[2]._b,
                ]
            )
        elif isinstance(p, potential.KuzminKutuzovStaeckelPotential):
            pot_type.append(16)
            pot_args.extend([p._amp, p._ac, p._Delta])
        elif isinstance(p, potential.PlummerPotential):
            pot_type.append(17)
            pot_args.extend([p._amp, p._b])
        elif isinstance(p, potential.PseudoIsothermalPotential):
            pot_type.append(18)
            pot_args.extend([p._amp, p._a])
        elif isinstance(p, potential.KuzminDiskPotential):
            pot_type.append(19)
            pot_args.extend([p._amp, p._a])
        elif isinstance(p, potential.BurkertPotential):
            pot_type.append(20)
            pot_args.extend([p._amp, p.a])
        elif isinstance(p, potential.EllipsoidalPotential.EllipsoidalPotential):
            pot_args.append(p._amp)
            pot_args.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])  # for caching
            # Potential specific parameters
            if isinstance(p, potential.TriaxialHernquistPotential):
                pot_type.append(21)
                pot_args.extend([2, p.a, p.a4])  # for psi, mdens, mdens_deriv
            elif isinstance(p, potential.TriaxialNFWPotential):
                pot_type.append(22)
                pot_args.extend([2, p.a, p.a3])  # for psi, mdens, mdens_deriv
            elif isinstance(p, potential.TriaxialJaffePotential):
                pot_type.append(23)
                pot_args.extend([2, p.a, p.a2])  # for psi, mdens, mdens_deriv
            elif isinstance(p, potential.PerfectEllipsoidPotential):
                pot_type.append(30)
                pot_args.extend([1, p.a2])  # for psi, mdens, mdens_deriv
            elif isinstance(p, potential.TriaxialGaussianPotential):
                pot_type.append(37)
                pot_args.extend([1, -p._twosigma2])  # for psi, mdens, mdens_deriv
            elif isinstance(p, potential.PowerTriaxialPotential):
                pot_type.append(38)
                pot_args.extend([1, p.alpha])  # for psi, mdens, mdens_deriv
            pot_args.extend([p._b2, p._c2, int(p._aligned)])  # Reg. Ellipsoidal
            if not p._aligned:
                pot_args.extend(list(p._rot.flatten()))
            else:
                pot_args.extend(list(numpy.eye(3).flatten()))  # not actually used
            pot_args.append(p._glorder)
            pot_args.extend([p._glx[ii] for ii in range(p._glorder)])
            # this adds some common factors to the integration weights
            pot_args.extend(
                [
                    -4.0
                    * numpy.pi
                    * p._glw[ii]
                    * p._b
                    * p._c
                    / numpy.sqrt(
                        (1.0 + (p._b2 - 1.0) * p._glx[ii] ** 2.0)
                        * (1.0 + (p._c2 - 1.0) * p._glx[ii] ** 2.0)
                    )
                    for ii in range(p._glorder)
                ]
            )
        elif isinstance(p, potential.SCFPotential):
            # Type 24, see stand-alone parser below
            pt, pa, ptf = _parse_scf_pot(p)
            pot_type.append(pt)
            pot_args.extend(pa)
            pot_tfuncs.extend(ptf)
        elif isinstance(p, potential.SoftenedNeedleBarPotential):
            pot_type.append(25)
            pot_args.extend([p._amp, p._a, p._b, p._c2, p._pa, p._omegab])
            pot_args.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])  # for caching
        elif isinstance(p, potential.DiskSCFPotential):
            # Need to pull this apart into: (a) SCF part, (b) constituent
            # [Sigma_i,h_i] parts
            # (a) SCF, multiply in any add'l amp
            pt, pa, ptf = _parse_scf_pot(p._scf, extra_amp=p._amp)
            pot_type.append(pt)
            pot_args.extend(pa)
            pot_tfuncs.extend(ptf)
            # (b) constituent [Sigma_i,h_i] parts
            for Sigma, hz in zip(p._Sigma_dict, p._hz_dict):
                npot += 1
                pot_type.append(26)
                stype = Sigma.get("type", "exp")
                if stype == "exp" and not "Rhole" in Sigma:
                    pot_args.extend(
                        [
                            3,
                            0,
                            4.0 * numpy.pi * Sigma.get("amp", 1.0) * p._amp,
                            Sigma.get("h", 1.0 / 3.0),
                        ]
                    )
                elif stype == "expwhole" or (stype == "exp" and "Rhole" in Sigma):
                    pot_args.extend(
                        [
                            4,
                            1,
                            4.0 * numpy.pi * Sigma.get("amp", 1.0) * p._amp,
                            Sigma.get("h", 1.0 / 3.0),
                            Sigma.get("Rhole", 0.5),
                        ]
                    )
                hztype = hz.get("type", "exp")
                if hztype == "exp":
                    pot_args.extend([0, hz.get("h", 0.0375)])
                elif hztype == "sech2":
                    pot_args.extend([1, hz.get("h", 0.0375)])
        elif isinstance(p, potential.SpiralArmsPotential):
            pot_type.append(27)
            pot_args.extend(
                [
                    len(p._Cs),
                    p._amp,
                    p._N,
                    p._sin_alpha,
                    p._tan_alpha,
                    p._r_ref,
                    p._phi_ref,
                    p._Rs,
                    p._H,
                    p._omega,
                ]
            )
            pot_args.extend(p._Cs)
        # 30: PerfectEllipsoidPotential, done with others above
        # 31: KGPotential
        # 32: IsothermalDiskPotential
        elif isinstance(p, potential.DehnenCoreSphericalPotential):
            pot_type.append(33)
            pot_args.extend([p._amp, p.a])
        elif isinstance(p, potential.DehnenSphericalPotential):
            pot_type.append(34)
            pot_args.extend([p._amp, p.a, p.alpha])
        elif isinstance(p, potential.HomogeneousSpherePotential):
            pot_type.append(35)
            pot_args.extend([p._amp, p._R2, p._R3])
        elif isinstance(p, potential.interpSphericalPotential):
            pot_type.append(36)
            pot_args.append(len(p._rgrid))
            pot_args.extend(p._rgrid)
            pot_args.extend(p._rforce_grid)
            pot_args.extend(
                [p._amp, p._rmin, p._rmax, p._total_mass, p._Phi0, p._Phimax]
            )
        # 37: TriaxialGaussianPotential, done with others above
        # 38: PowerTriaxialPotential, done with others above
        elif isinstance(p, potential.NonInertialFrameForce):
            pot_type.append(39)
            pot_args.append(p._amp)
            pot_args.extend(
                [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
            )  # for caching
            pot_args.extend(
                [
                    p._rot_acc,
                    p._lin_acc,
                    p._omegaz_only,
                    p._const_freq,
                    p._Omega_as_func,
                ]
            )
            if p._Omega_as_func:
                pot_args.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
            else:
                if p._omegaz_only:
                    pot_args.extend([0.0, 0.0, p._Omega])
                else:
                    pot_args.extend(p._Omega)
                pot_args.append(p._Omega2)
                if not p._const_freq and p._omegaz_only:
                    pot_args.extend([0.0, 0.0, p._Omegadot])
                elif not p._const_freq:
                    pot_args.extend(p._Omegadot)
                else:
                    pot_args.extend([0.0, 0.0, 0.0])
            if p._lin_acc:
                pot_tfuncs.extend([p._a0[0], p._a0[1], p._a0[2]])
                if p._rot_acc:
                    pot_tfuncs.extend([p._x0[0], p._x0[1], p._x0[2]])
                    pot_tfuncs.extend([p._v0[0], p._v0[1], p._v0[2]])
            if p._Omega_as_func:
                if p._omegaz_only:
                    pot_tfuncs.extend([p._Omega, p._Omegadot])
                else:
                    pot_tfuncs.extend(
                        [
                            p._Omega[0],
                            p._Omega[1],
                            p._Omega[2],
                            p._Omegadot[0],
                            p._Omegadot[1],
                            p._Omegadot[2],
                        ]
                    )
        elif isinstance(p, potential.NullPotential):
            pot_type.append(40)
            # No arguments, zero forces
        ############################## WRAPPERS ###############################
        elif isinstance(p, potential.DehnenSmoothWrapperPotential):
            pot_type.append(-1)
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([p._amp, p._tform, p._tsteady, int(p._grow)])
        elif isinstance(p, potential.SolidBodyRotationWrapperPotential):
            pot_type.append(-2)
            # Not sure how to easily avoid this duplication
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([p._amp, p._omega, p._pa])
        elif isinstance(p, potential.CorotatingRotationWrapperPotential):
            pot_type.append(-4)
            # Not sure how to easily avoid this duplication
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([p._amp, p._vpo, p._beta, p._pa, p._to])
        elif isinstance(p, potential.GaussianAmplitudeWrapperPotential):
            pot_type.append(-5)
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([p._amp, p._to, p._sigma2])
        elif isinstance(p, potential.MovingObjectPotential):
            pot_type.append(-6)
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([len(p._orb.t)])
            pot_args.extend(p._orb.t)
            pot_args.extend(p._orb.x(p._orb.t, use_physical=False))
            pot_args.extend(p._orb.y(p._orb.t, use_physical=False))
            pot_args.extend(p._orb.z(p._orb.t, use_physical=False))
            pot_args.extend([p._amp])
            pot_args.extend([p._orb.t[0], p._orb.t[-1]])  # t_0, t_f
        elif isinstance(p, potential.ChandrasekharDynamicalFrictionForce):
            pot_type.append(-7)
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._dens_pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([len(p._sigmar_rs_4interp)])
            pot_args.extend(p._sigmar_rs_4interp)
            pot_args.extend(p._sigmars_4interp)
            pot_args.extend([p._amp])
            pot_args.extend([-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])  # for caching
            pot_args.extend(
                [
                    p._ms,
                    p._rhm,
                    p._gamma**2.0,
                    -1 if not p._lnLambda else p._lnLambda,
                    p._minr**2.0,
                ]
            )
            pot_args.extend(
                [p._sigmar_rs_4interp[0], p._sigmar_rs_4interp[-1]]
            )  # r_0, r_f
        elif isinstance(p, potential.RotateAndTiltWrapperPotential):
            pot_type.append(-8)
            # Not sure how to easily avoid this duplication
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([p._amp])
            pot_args.extend([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])  # for caching
            pot_args.extend(list(p._rot.flatten()))
            pot_args.append(not p._norot)
            pot_args.append(not p._offset is None)
            pot_args.extend(
                list(p._offset) if not p._offset is None else [0.0, 0.0, 0.0]
            )
        elif isinstance(p, potential.TimeDependentAmplitudeWrapperPotential):
            pot_type.append(-9)
            # Not sure how to easily avoid this duplication
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.append(p._amp)
            pot_tfuncs.append(p._A)
        elif isinstance(p, potential.KuzminLikeWrapperPotential):
            pot_type.append(-10)
            # Not sure how to easily avoid this duplication
            wrap_npot, wrap_pot_type, wrap_pot_args, wrap_pot_tfuncs = _parse_pot(
                p._pot, potforactions=potforactions, potfortorus=potfortorus
            )
            pot_args.append(wrap_npot)
            pot_type.extend(wrap_pot_type)
            pot_args.extend(wrap_pot_args)
            pot_tfuncs.extend(wrap_pot_tfuncs)
            pot_args.extend([p._amp, p._a, p._b2])
    pot_type = numpy.array(pot_type, dtype=numpy.int32, order="C")
    pot_args = numpy.array(pot_args, dtype=numpy.float64, order="C")
    return (npot, pot_type, pot_args, pot_tfuncs)