desc: >
            Creates a DocStringArg and recursively includes child
            docstrings if they are not JSON types.
        args:
            -   name: name
                desc: The name of the argument
                type: str
            -   name: desc
                desc: A description of the argument
                type: str
            -   name: type
                desc: The type of the argument
                type: str
            -   name: subtypes
                desc: >
                    If @type is a list, dict or other data structure,
                    the contained objects should be of this type.
                    This should be a list of one item for lists, or a list
                    of 2 items for a dict.  More than 2 items is not
                    supported.
                type: list
                required: false
                default: None
            -   name: required
                desc: >
                    True if this is a mandatory argument, False if it
                    has a default value.  If False, @default should be
                    set appropriately.
                type: bool
                required: false
                default: true
            -   name: default
                desc: >
                    The default value for this argument.  This is ignored
                    if @required == True
                type: any
            -   name: ctor
                desc: >
                    Only use if @type is a class instance and not a JSON type
                    The constructor that the JSON object will be
                    unmarshalled to.  Either the Class.__init__, or a
                    factory function or factory static method.
                    Use the full path: module.submodule.Class.__init__
                type: str
                required: false
                default: None
            -   name: hide
                desc: >
                    Don't display this argument to the user.  Useful for
                    not showing arguments that are excluded from marshalling.
                    Note that this is only a hint to the client that will
                    render the JSON, the argument will still be sent
                required: false
                type: bool
                default: false
        returns:
            desc: A DocStringArg instance with recursively populated
                  @docstring attributes for child arguments
            type: pymarshal.api_docs.docstring.DocStringArg

def factory(
        name,
        desc,
        type,
        subtypes=None,
        required=True,
        default=None,
        ctor=None,
        hide=False,
    ):
        """
        desc: >
            Creates a DocStringArg and recursively includes child
            docstrings if they are not JSON types.
        args:
            -   name: name
                desc: The name of the argument
                type: str
            -   name: desc
                desc: A description of the argument
                type: str
            -   name: type
                desc: The type of the argument
                type: str
            -   name: subtypes
                desc: >
                    If @type is a list, dict or other data structure,
                    the contained objects should be of this type.
                    This should be a list of one item for lists, or a list
                    of 2 items for a dict.  More than 2 items is not
                    supported.
                type: list
                required: false
                default: None
            -   name: required
                desc: >
                    True if this is a mandatory argument, False if it
                    has a default value.  If False, @default should be
                    set appropriately.
                type: bool
                required: false
                default: true
            -   name: default
                desc: >
                    The default value for this argument.  This is ignored
                    if @required == True
                type: any
            -   name: ctor
                desc: >
                    Only use if @type is a class instance and not a JSON type
                    The constructor that the JSON object will be
                    unmarshalled to.  Either the Class.__init__, or a
                    factory function or factory static method.
                    Use the full path: module.submodule.Class.__init__
                type: str
                required: false
                default: None
            -   name: hide
                desc: >
                    Don't display this argument to the user.  Useful for
                    not showing arguments that are excluded from marshalling.
                    Note that this is only a hint to the client that will
                    render the JSON, the argument will still be sent
                required: false
                type: bool
                default: false
        returns:
            desc: A DocStringArg instance with recursively populated
                  @docstring attributes for child arguments
            type: pymarshal.api_docs.docstring.DocStringArg
        """
        if ctor:
            type_assert(ctor, str)
            module_name, cls_name, method_name = ctor.rsplit('.', 2)
            module = importlib.import_module(module_name)
            cls = getattr(module, cls_name)
            method = getattr(cls, method_name)
            docstring = DocString.from_ctor(method)
        else:
            docstring = None

        return DocStringArg(
            name,
            desc,
            type,
            subtypes,
            required,
            default,
            docstring=docstring,
            hide=hide,
        )