Repository: scipy/scipy
File: scipy/optimize/_minpack_py.py (Python)

Code before:
    ...     popt, pcov = curve_fit(func, xdata, ydata, method = 'trf')
    ... except RuntimeError as e:
    ...     print(e)
    Optimal parameters not found: The maximum number of function evaluations is
    exceeded.

    If parameter scale is roughly known beforehand, it can be defined in
    `x_scale` argument:

    >>> popt, pcov = curve_fit(func, xdata, ydata, method = 'trf',
    ...                        x_scale = [1000, 1, 1])
    >>> popt
    array([5.00000000e+05, 1.00000000e-02, 1.49999999e+01])
    """
    if p0 is None:
        # determine number of parameters by inspecting the function
        #
        # NOTE: This implementation is made to match previous behavior. However,
        #       inspect.Parameter.POSITIONAL_ONLY parameters would still match
        #       documented signature, e.g., f(x, a_1, a_2, / ,...), but are
        #       ignored here. Can trigger misleading behavior.
        args = [
            v for v in wrapped_inspect_signature(f).parameters.values()
            if v.kind in [inspect.Parameter.POSITIONAL_OR_KEYWORD,
                          inspect.Parameter.KEYWORD_ONLY]
        ]
        if len(args) < 2:
            raise ValueError("Unable to determine number of fit parameters.")
        n = len(args) - 1
    else:
        p0 = np.atleast_1d(p0)
        n = p0.size

    if isinstance(bounds, Bounds):
        lb, ub = bounds.lb, bounds.ub
    else:
        lb, ub = prepare_bounds(bounds, n)
    if p0 is None:
        p0 = _initialize_feasible(lb, ub)

    bounded_problem = np.any((lb > -np.inf) | (ub < np.inf))
    if method is None:
        if bounded_problem:
            method = 'trf'
        else:
            method = 'lm'

    if method == 'lm' and bounded_problem:
        raise ValueError("Method 'lm' only works for unconstrained problems. "
                         "Use 'trf' or 'dogbox' instead.")


Review comment (suggestion):
Rather than make this change, can you fix `getfullargspec_no_self()` instead? That has many callers, and likely almost none of them care about annotations. (The name refers to a legacy API, so anything calling this was likely written before annotations existed.)

Code after:
    ... except RuntimeError as e:
    ...     print(e)
    Optimal parameters not found: The maximum number of function evaluations is
    exceeded.

    If parameter scale is roughly known beforehand, it can be defined in
    `x_scale` argument:

    >>> popt, pcov = curve_fit(func, xdata, ydata, method = 'trf',
    ...                        x_scale = [1000, 1, 1])
    >>> popt
    array([5.00000000e+05, 1.00000000e-02, 1.49999999e+01])
    """
    if p0 is None:
        # determine number of parameters by inspecting the function
        sig = _getfullargspec(f)
        args = sig.args
        if len(args) < 2:
            raise ValueError("Unable to determine number of fit parameters.")
        n = len(args) - 1
    else:
        p0 = np.atleast_1d(p0)
        n = p0.size

    if isinstance(bounds, Bounds):
        lb, ub = bounds.lb, bounds.ub
    else:
        lb, ub = prepare_bounds(bounds, n)
    if p0 is None:
        p0 = _initialize_feasible(lb, ub)

    bounded_problem = np.any((lb > -np.inf) | (ub < np.inf))
    if method is None:
        if bounded_problem:
            method = 'trf'
        else:
            method = 'lm'

    if method == 'lm' and bounded_problem:
        raise ValueError("Method 'lm' only works for unconstrained problems. "
                         "Use 'trf' or 'dogbox' instead.")

    if check_finite is None:
        check_finite = True if nan_policy is None else False

    # optimization may produce garbage for float32 inputs, cast them to float64
    if check_finite:
        ydata = np.asarray_chkfinite(ydata, float)
    else:
        ydata = np.asarray(ydata, float)