maya python export curves

```Python
import json
import logging
import maya.cmds as cmds
import maya.api.OpenMaya as OpenMaya

logger = logging.getLogger(__name__)

def export_curves(controls=None, file_path=None):
    """Serializes the given curves into the control library.

    :param controls: Optional list of controls to export. If no controls are specified,
        the selected curves will be exported.
    :param file_path: File path to export to
    :return: The exported list of ControlShapes.
    """
    if controls is None:
        controls = cmds.ls(sl=True)
    data = get_curve_data(controls)
    with open(file_path, "w") as fh:
        json.dump(data, fh, indent=4, cls=CurveShapeEncoder)
        logger.info("Exported controls to {}".format(file_path))
    return data

def import_curves(file_path=None, tag_as_controller=False):
    """Imports control shapes from disk onto their saved named transforms.

    :param file_path: Path to the control file.
    :param tag_as_controller: True to tag the curve transform as a controller
    :return: The new curve transforms
    """
    controls = load_curves(file_path)

    transforms = [
        curve.create(curve.transform, tag_as_controller) for curve in controls
    ]
    return transforms

def get_curve_data(controls=None):
    """Get the serializable data of the given controls.

    :param controls: Controls to serialize
    :return: List of ControlShape objects
    """
    if controls is None:
        controls = cmds.ls(sl=True)
    data = [CurveShape(transform=control) for control in controls]
    # Prune empty curves
    data = [x for x in data if x.cvs]
    return data

def load_curves(file_path=None):
    """Load the CurveShape objects from disk.

    :param file_path:
    :return:
    """

    with open(file_path, "r") as fh:
        data = json.load(fh)
    logger.info("Loaded controls {}".format(file_path))
    curves = [CurveShape(**control) for control in data]
    return curves

def get_shape(node, intermediate=False):
    """Get the shape node of a tranform

    This is useful if you don't want to have to check if a node is a shape node
    or transform.  You can pass in a shape node or transform and the function
    will return the shape node.

    :param node:  node The name of the node.
    :param intermediate:  intermediate True to get the intermediate shape
    :return: The name of the shape node.
    """
    if cmds.objectType(node, isAType="transform"):
        shapes = cmds.listRelatives(node, shapes=True, path=True)
        if not shapes:
            shapes = []
        for shape in shapes:
            is_intermediate = cmds.getAttr("{}.intermediateObject".format(shape))
            if (
                intermediate
                and is_intermediate
                and cmds.listConnections(shape, source=False)
            ):
                return shape
            elif not intermediate and not is_intermediate:
                return shape
        if shapes:
            return shapes[0]
    elif cmds.nodeType(node) in ["mesh", "nurbsCurve", "nurbsSurface"]:
        is_intermediate = cmds.getAttr("{}.intermediateObject".format(node))
        if is_intermediate and not intermediate:
            node = cmds.listRelatives(node, parent=True, path=True)[0]
            return get_shape(node)
        else:
            return node
    return None

def get_knots(curve):
    """Gets the list of knots of a curve so it can be recreated.

    :param curve: Curve to query.
    :return: A list of knot values that can be passed into the curve creation command.
    """
    curve = get_shape(curve)
    info = cmds.createNode("curveInfo")
    cmds.connectAttr("{0}.worldSpace".format(curve), "{0}.inputCurve".format(info))
    knots = cmds.getAttr("{0}.knots[*]".format(info))
    knots = [int(x) for x in knots]
    cmds.delete(info)
    return knots

class CurveShape(object):
    """Represents the data required to build a nurbs curve shape"""

    def __init__(
        self, transform=None, cvs=None, degree=3, form=0, knots=None, color=None
    ):
        self.cvs = cvs
        self.degree = degree
        self.form = form
        self.knots = knots
        self.color = color
        self.transform_matrix = OpenMaya.MTransformationMatrix()
        self.transform = transform
        if transform and cmds.objExists(transform) and not cvs:
            self._set_from_curve(transform)

    def _set_from_curve(self, transform):
        """Store the parameters from an existing curve in the CurveShape object.

        :param transform: Transform
        """
        shape = get_shape(transform)
        if shape and cmds.nodeType(shape) == "nurbsCurve":
            create_attr = "{}.create".format(shape)
            connection = cmds.listConnections(create_attr, plugs=True, d=False)
            if connection:
                cmds.disconnectAttr(connection[0], create_attr)
            self.transform = transform
            self.cvs = cmds.getAttr("{}.cv[*]".format(shape))
            self.degree = cmds.getAttr("{}.degree".format(shape))
            self.form = cmds.getAttr("{}.form".format(shape))
            self.knots = get_knots(shape)
            if cmds.getAttr("{}.overrideEnabled".format(shape)):
                if cmds.getAttr("{}.overrideRGBColors".format(shape)):
                    self.color = cmds.getAttr("{}.overrideColorRGB".format(shape))[0]
                else:
                    self.color = cmds.getAttr("{}.overrideColor".format(shape))
            else:
                self.color = None
            if connection:
                cmds.connectAttr(connection[0], create_attr)

    def create(self, transform=None, as_controller=True):
        """Create a curve.

        :param transform: Name of the transform to create the curve shape under.
            If the transform does not exist, it will be created.
        :param as_controller: True to mark the curve transform as a controller.
        :return: The transform of the new curve shapes.
        """
        transform = transform or self.transform
        if not cmds.objExists(transform):
            transform = cmds.createNode("transform", name=transform)
        periodic = self.form == 2
        points = self._get_transformed_points()
        points = points + points[: self.degree] if periodic else points
        curve = cmds.curve(degree=self.degree, p=points, per=periodic, k=self.knots)
        shape = get_shape(curve)
        if self.color is not None:
            cmds.setAttr("{}.overrideEnabled".format(shape), True)
            if isinstance(self.color, int):
                cmds.setAttr("{}.overrideColor".format(shape), self.color)
            else:
                cmds.setAttr("{}.overrideRGBColors".format(shape), True)
                cmds.setAttr("{}.overrideColorRGB".format(shape), *self.color)
        cmds.parent(shape, transform, r=True, s=True)
        shape = cmds.rename(shape, "{}Shape".format(transform))
        cmds.delete(curve)
        if as_controller:
            cmds.controller(transform)
        logger.info("Created curve {} for transform {}".format(shape, transform))
        return transform

    def _get_transformed_points(self):
        matrix = self.transform_matrix.asMatrix()
        points = [OpenMaya.MPoint(*x) * matrix for x in self.cvs]
        points = [(p.x, p.y, p.z) for p in points]
        return points

    def translate_by(self, x, y, z, local=True):
        """Translate the curve cvs by the given values

        :param x: Translate X
        :param y: Translate Y
        :param z: Translate Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.translateBy(OpenMaya.MVector(x, y, z), space)

    def set_translation(self, x, y, z, local=True):
        """Set the absolute translation of the curve shape.

        :param x: Translate X
        :param y: Translate Y
        :param z: Translate Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.setTranslation(OpenMaya.MVector(x, y, z), space)

    def rotate_by(self, x, y, z, local=True):
        """Rotate the curve cvs by the given euler rotation values

        :param x: Rotate X
        :param y: Rotate Y
        :param z: Rotate Z
        :param local: True for local space, False for world
        """
        x, y, z = [v * 0.0174533 for v in [x, y, z]]
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.rotateBy(OpenMaya.MEulerRotation(x, y, z), space)

    def set_rotation(self, x, y, z):
        """Set the absolute rotation of the curve shape in euler rotations.

        :param x: Rotate X
        :param y: Rotate Y
        :param z: Rotate Z
        """
        x, y, z = [v * 0.0174533 for v in [x, y, z]]
        self.transform_matrix.setRotation(OpenMaya.MEulerRotation(x, y, z))

    def scale_by(self, x, y, z, local=True):
        """Scale the curve cvs by the given amount.

        :param x: Scale X
        :param y: Scale Y
        :param z: Scale Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.scaleBy([x, y, z], space)

    def set_scale(self, x, y, z, local=True):
        """Set the absolute scale of the curve shape.

        :param x: Scale X
        :param y: Scale Y
        :param z: Scale Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.setScale([x, y, z], space)

def ExportCurves():
    curve_transforms = [cmds.listRelatives(i, p=1, type='transform')[0] for i
    in cmds.ls(type='nurbsCurve', o=1, r=1, ni=1)]
    selectList = []
    for c in curve_transforms:
        if "RootX_M" in c or "Neck_M" in c:
            selectList.append(c)

    file_path = "D:/curves.json"
    export_curves(selectList, file_path)

def ImportCurves():
    file_path = "D:/curves.json"
    import_curves(file_path, True)

#ExportCurves()
ImportCurves()
```