Repository: scikit-learn/scikit-learn
File: sklearn/svm/tests/test_svm.py (Python)

Code before:
        svm.OneClassSVM(kernel="linear").fit(iris.data),
    ]
    for clf in svms:
        with pytest.raises(AttributeError):
            clf.__setattr__("coef_", np.arange(3))
        with pytest.raises((RuntimeError, ValueError)):
            clf.coef_.__setitem__((0, 0), 0)


@pytest.mark.thread_unsafe
def test_linearsvc_verbose():
    # stdout: redirect
    import os

    stdout = os.dup(1)  # save original stdout
    os.dup2(os.pipe()[1], 1)  # replace it

    # actual call
    clf = svm.LinearSVC(verbose=1)
    clf.fit(X, Y)

    # stdout: restore
    os.dup2(stdout, 1)  # restore original stdout


# XXX: this test is thread-unsafe because it uses probability=True
# https://github.com/scikit-learn/scikit-learn/issues/31885
@pytest.mark.thread_unsafe
def test_svc_clone_with_callable_kernel():
    iris = get_iris_dataset(42)

    # create SVM with callable linear kernel, check that results are the same
    # as with built-in linear kernel
    svm_callable = svm.SVC(
        kernel=lambda x, y: np.dot(x, y.T),
        random_state=0,
        decision_function_shape="ovr",
    )
    # clone for checking clonability with lambda functions..
    svm_cloned = base.clone(svm_callable)
    svm_cloned.fit(iris.data, iris.target)

    svm_builtin = svm.SVC(
        kernel="linear",
        random_state=0,
        decision_function_shape="ovr",
    )

    svm_builtin.fit(iris.data, iris.target)

    assert_array_almost_equal(svm_cloned.dual_coef_, svm_builtin.dual_coef_)

Review comment (bug):
I guess the comment and `pytest.mark.tread_unsafe` can be removed since `probability=True` is not used anymore, right?

It would be nice to double-check with a free-threaded python

You can install free-threaded Python like this with conda/mamba
```
mamba create -n py314t python-freeethreading python
```

and then install pytest-run-parallel and run the tests like this (maybe a few times to make 99.9% sure that there is no failure)

```
pytest --parallel-threads 4 --iterations 10 sklearn/svm/tests/test_svm.py -k test_svc_clone_with_callable_kernel
```

Code after:
        svm.NuSVR(kernel="linear").fit(iris.data, iris.target),
        svm.OneClassSVM(kernel="linear").fit(iris.data),
    ]
    for clf in svms:
        with pytest.raises(AttributeError):
            clf.__setattr__("coef_", np.arange(3))
        with pytest.raises((RuntimeError, ValueError)):
            clf.coef_.__setitem__((0, 0), 0)


@pytest.mark.thread_unsafe
def test_linearsvc_verbose():
    # stdout: redirect
    import os

    stdout = os.dup(1)  # save original stdout
    os.dup2(os.pipe()[1], 1)  # replace it

    # actual call
    clf = svm.LinearSVC(verbose=1)
    clf.fit(X, Y)

    # stdout: restore
    os.dup2(stdout, 1)  # restore original stdout


def test_svc_clone_with_callable_kernel():
    iris = get_iris_dataset(42)

    # create SVM with callable linear kernel, check that results are the same
    # as with built-in linear kernel
    svm_callable = svm.SVC(
        kernel=lambda x, y: np.dot(x, y.T),
        random_state=0,
        decision_function_shape="ovr",
    )
    # clone for checking clonability with lambda functions..
    svm_cloned = base.clone(svm_callable)
    svm_cloned.fit(iris.data, iris.target)

    svm_builtin = svm.SVC(
        kernel="linear",
        random_state=0,
        decision_function_shape="ovr",
    )

    svm_builtin.fit(iris.data, iris.target)

    assert_array_almost_equal(svm_cloned.dual_coef_, svm_builtin.dual_coef_)
    assert_array_almost_equal(svm_cloned.intercept_, svm_builtin.intercept_)
    assert_array_equal(svm_cloned.predict(iris.data), svm_builtin.predict(iris.data))