<!-- Thank you for contributing to Pyodide! All improvements are welcome,
     so don't be afraid to make a PR. -->

<!-- [IMPORTANT] Note on CI failures:
     Currently, we are having issues with selenium-based tests.
     Don't panic if the CI fails on your PR because of timeouts.
     It's probably not your fault. We will investigate :) -->

### Description

<!-- Please explain what your PR is about:
     - reasoning for the change
     - some details of updated code
     - any noteworthy choices to be aware of
	Please refer to any related issues by #<issue_id> -->

Working on using pre-commit properly. Will be a series of commits, and undrafted after they are complete.

Rough plan:

- [x] Commit 1: update pre-commit, prepare mypy to run correctly.
- [x] Next commit: apply pre-commit fixes
- [x] Next commit: use pre-commit instead of manual runs inside Makefile.
- [x] Somewhere in between commit: fix manual issues

### Checklists

<!-- Note on checklists:
     If you think some of these steps are not necessary for your PR,
     just remove those checkboxes, or mark them as checked. Otherwise,
     if some checkboxes are left unmarked, we might assume that your PR
     is not ready to be merged and we might keep you waiting -->

style: improve pre-commit. <!-- Thank you for contributing to Pyodide! All improvements are welcome,
     so don't be afraid to make a PR. -->

<!-- [IMPORTANT] Note on CI failures:
     Currently, we are having issues with selenium-based tests.
     Don't panic if the CI fails on your PR because of timeouts.
     It's probably not your fault. We will investigate :) -->

### Description

<!-- Please explain what your PR is about:
     - reasoning for the change
     - some details of updated code
     - any noteworthy choices to be aware of
	Please refer to any related issues by #<issue_id> -->

Working on using pre-commit properly. Will be a series of commits, and undrafted after they are complete.

Rough plan:

- [x] Commit 1: update pre-commit, prepare mypy to run correctly.
- [x] Next commit: apply pre-commit fixes
- [x] Next commit: use pre-commit instead of manual runs inside Makefile.
- [x] Somewhere in between commit: fix manual issues

### Checklists

<!-- Note on checklists:
     If you think some of these steps are not necessary for your PR,
     just remove those checkboxes, or mark them as checked. Otherwise,
     if some checkboxes are left unmarked, we might assume that your PR
     is not ready to be merged and we might keep you waiting -->

from pyodide_build.testing import run_in_pyodide


@run_in_pyodide(packages=["wrapt"])
def test_wrapt():
    import wrapt
    import unittest

    @wrapt.decorator
    def passthru_decorator(wrapped, instance, args, kwargs):
        return wrapped(*args, **kwargs)

    def function1(arg):
        """documentation"""
        return arg

    function1o = function1
    function1d = passthru_decorator(function1)
    assert function1d is not function1o

    class TestNamingFunction(unittest.TestCase):
        def test_object_name(self):
            # Test preservation of function __name__ attribute.

            self.assertEqual(function1d.__name__, function1o.__name__)

        def test_object_qualname(self):
            # Test preservation of function __qualname__ attribute.

            try:
                __qualname__ = function1o.__qualname__
            except AttributeError:
                pass
            else:
                self.assertEqual(function1d.__qualname__, __qualname__)

        def test_module_name(self):
            # Test preservation of function __module__ attribute.

            self.assertEqual(function1d.__module__, __name__)

        def test_doc_string(self):
            # Test preservation of function __doc__ attribute.

            self.assertEqual(function1d.__doc__, function1o.__doc__)

        def test_argspec(self):
            # Test preservation of function argument specification.

            function1o_argspec = inspect.getargspec(function1o)
            function1d_argspec = inspect.getargspec(function1d)
            self.assertEqual(function1o_argspec, function1d_argspec)

        def test_getmembers(self):
            function1o_members = inspect.getmembers(function1o)
            function1d_members = inspect.getmembers(function1d)

        def test_isinstance(self):
            # Test preservation of isinstance() checks.

            self.assertTrue(isinstance(function1d, type(function1o)))

    class TestCallingFunction(unittest.TestCase):
        def test_call_function(self):
            _args = (1, 2)
            _kwargs = {"one": 1, "two": 2}

            @wrapt.decorator
            def _decorator(wrapped, instance, args, kwargs):
                self.assertEqual(instance, None)
                self.assertEqual(args, _args)
                self.assertEqual(kwargs, _kwargs)
                return wrapped(*args, **kwargs)

            @_decorator
            def _function(*args, **kwargs):
                return args, kwargs

            result = _function(*_args, **_kwargs)

            self.assertEqual(result, (_args, _kwargs))

from pyodide_build.testing import run_in_pyodide


@run_in_pyodide(packages=["wrapt"])
def test_wrapt():
    import wrapt
    import unittest

    @wrapt.decorator
    def passthru_decorator(wrapped, instance, args, kwargs):
        return wrapped(*args, **kwargs)

    def function1(arg):
        """documentation"""
        return arg

    function1o = function1
    function1d = passthru_decorator(function1)
    assert function1d is not function1o

    class TestNamingFunction(unittest.TestCase):
        def test_object_name(self):
            # Test preservation of function __name__ attribute.

            self.assertEqual(function1d.__name__, function1o.__name__)

        def test_object_qualname(self):
            # Test preservation of function __qualname__ attribute.

            try:
                __qualname__ = function1o.__qualname__
            except AttributeError:
                pass
            else:
                self.assertEqual(function1d.__qualname__, __qualname__)

        def test_module_name(self):
            # Test preservation of function __module__ attribute.

            self.assertEqual(function1d.__module__, __name__)

        def test_doc_string(self):
            # Test preservation of function __doc__ attribute.

            self.assertEqual(function1d.__doc__, function1o.__doc__)

        def test_argspec(self):
            # Test preservation of function argument specification.

            function1o_argspec = inspect.getargspec(function1o)
            function1d_argspec = inspect.getargspec(function1d)
            self.assertEqual(function1o_argspec, function1d_argspec)

        def test_getmembers(self):
            function1o_members = inspect.getmembers(function1o)
            function1d_members = inspect.getmembers(function1d)

        def test_isinstance(self):
            # Test preservation of isinstance() checks.

            self.assertTrue(isinstance(function1d, type(function1o)))

    class TestCallingFunction(unittest.TestCase):
        def test_call_function(self):
            _args = (1, 2)
            _kwargs = {"one": 1, "two": 2}

            @wrapt.decorator
            def _decorator(wrapped, instance, args, kwargs):
                self.assertEqual(instance, None)
                self.assertEqual(args, _args)
                self.assertEqual(kwargs, _kwargs)
                return wrapped(*args, **kwargs)

            @_decorator
            def _function(*args, **kwargs):
                return args, kwargs

            result = _function(*_args, **_kwargs)

            self.assertEqual(result, (_args, _kwargs))
