This changes the calling convention for calling a Javascript function from Python so that any proxied arguments are automatically destroyed at the end of the function call. This is a breaking change. It should make it much more convenient to use the foreign function interface. 

The docs need to be updated to explain the new calling convention before this can be merged. We should put a link to the appropriate section in the docs into the error message emitted when a borrowed proxy is used after it is free so that people have an easy time learning the model by trial and error.
ENH Destroy proxies created in JsProxy.__call__ when done with call. This changes the calling convention for calling a Javascript function from Python so that any proxied arguments are automatically destroyed at the end of the function call. This is a breaking change. It should make it much more convenient to use the foreign function interface. 

The docs need to be updated to explain the new calling convention before this can be merged. We should put a link to the appropriate section in the docs into the error message emitted when a borrowed proxy is used after it is free so that people have an easy time learning the model by trial and error.
import pytest


def test_threading_import(selenium):
    # Importing threading works
    selenium.run(
        """
        from threading import Thread
        """
    )

    selenium.run(
        """
        from threading import RLock

        with RLock():
            pass
        """
    )

    selenium.run(
        """
        from threading import Lock

        with Lock():
            pass
        """
    )

    selenium.run(
        """
        import threading
        threading.local(); pass
        """
    )

    # Starting a thread doesn't work
    msg = "can't start new thread"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run(
            """
            from threading import Thread

            def set_state():
                return
            th = Thread(target=set_state)
            th.start()
            """
        )


def test_multiprocessing(selenium):
    selenium.run("import multiprocessing")

    res = selenium.run(
        """
        from multiprocessing import cpu_count
        cpu_count()
        """
    )
    assert isinstance(res, int)
    assert res > 0

    msg = "Resource temporarily unavailable"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run(
            """
            from multiprocessing import Process

            def func():
                return
            process = Process(target=func)
            process.start()
            """
        )

import pytest


def test_threading_import(selenium):
    # Importing threading works
    selenium.run(
        """
        from threading import Thread
        """
    )

    selenium.run(
        """
        from threading import RLock

        with RLock():
            pass
        """
    )

    selenium.run(
        """
        from threading import Lock

        with Lock():
            pass
        """
    )

    selenium.run(
        """
        import threading
        threading.local(); pass
        """
    )

    # Starting a thread doesn't work
    msg = "can't start new thread"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run(
            """
            from threading import Thread

            def set_state():
                return
            th = Thread(target=set_state)
            th.start()
            """
        )


def test_multiprocessing(selenium):
    selenium.run("import multiprocessing")

    res = selenium.run(
        """
        from multiprocessing import cpu_count
        cpu_count()
        """
    )
    assert isinstance(res, int)
    assert res > 0

    msg = "Resource temporarily unavailable"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run(
            """
            from multiprocessing import Process

            def func():
                return
            process = Process(target=func)
            process.start()
            """
        )
