We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Incompatibility between `@angular_freq_to_hz` and var-keyword arguments
### Bug description

While trying to decorate `gyrofrequency` with `@particle_input` in #2026, I found an issue with `@angular_freq_to_hz`.  It appears that `@angular_freq_to_hz` cannot decorate functions that accept var-keyword arguments.

### Expected outcome

We should be able to use `@angular_freq_to_hz` to decorate functions with var-keyword parameters.

### Minimal complete verifiable example

When declaring this function:

```Python
from plasmapy.utils.decorators import angular_freq_to_hz
@angular_freq_to_hz
def f(**kwargs):
    return kwargs
```
I get:
```python
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[41], line 1
----> 1 @angular_freq_to_hz
      2 def f(**kwargs):
      3     return kwargs

File ~/Projects/PlasmaPy/plasmapy/utils/decorators/converter.py:101, in angular_freq_to_hz(fn)
     97 new_params = sig.parameters.copy()
     98 new_params["to_hz"] = inspect.Parameter(
     99     "to_hz", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=False
    100 )
--> 101 new_sig = inspect.Signature(
    102     parameters=new_params.values(), return_annotation=sig.return_annotation
    103 )
    104 fn.__signature__ = new_sig
    106 @preserve_signature
    107 @functools.wraps(fn)
    108 def wrapper(*args, to_hz=False, **kwargs):

File ~/miniconda3/envs/pldev/lib/python3.11/inspect.py:2994, in Signature.__init__(self, parameters, return_annotation, __validate_parameters__)
   2988     msg = (
   2989         'wrong parameter order: {} parameter before {} '
   2990         'parameter'
   2991     )
   2992     msg = msg.format(top_kind.description,
   2993                      kind.description)
-> 2994     raise ValueError(msg)
   2995 elif kind > top_kind:
   2996     kind_defaults = False

ValueError: wrong parameter order: variadic keyword parameter before positional or keyword parameter
```


### Package versions

Development branch 

### Additional context

This is medium priority to address since it's blocking #2026 and possibly also #2022.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `plasmapy/utils/decorators/converter.py`
Content:
```
1 """Decorators to convert units."""
2 
3 __all__ = ["angular_freq_to_hz"]
4 
5 import astropy.units as u
6 import functools
7 import inspect
8 
9 from plasmapy.utils.decorators.helpers import preserve_signature
10 
11 
12 def angular_freq_to_hz(fn):
13     """
14     A decorator that enables a function to convert its return
15     value from angular frequency (rad/s) to frequency (Hz).
16 
17     A kwarg ``to_hz`` is added to the function's signature, with a
18     default value of `False`.  The keyword is also added to the
19     function's docstring under the **"Other Parameters"** heading.
20 
21     Parameters
22     ----------
23     fn : function
24         The function to be decorated.
25 
26     Raises
27     ------
28     ValueError
29         If ``fn`` has already defined a kwarg ``to_hz``.
30 
31     Returns
32     -------
33     callable
34         The decorated function.
35 
36     Notes
37     -----
38     * If `~plasmapy.utils.decorators.converter.angular_freq_to_hz` is
39       used with decorator
40       :func:`~plasmapy.utils.decorators.validators.validate_quantities`,
41       then `angular_freq_to_hz` should be used inside
42       :func:`~plasmapy.utils.decorators.validators.validate_quantities`
43       but special consideration is needed for setup.  The following is
44       an example of an appropriate setup::
45 
46         import astropy.units as u
47         from plasmapy.utils.decorators.converter import angular_freq_to_hz
48         from plasmapy.utils.decorators.validators import validate_quantities
49 
50         @validate_quantities(validations_on_return={'units': [u.rad / u.s, u.Hz]})
51         @angular_freq_to_hz
52         def foo(x: u.rad / u.s) -> u.rad / u.s
53             return x
54 
55       Adding ``u.Hz`` to the allowed units allows the converted
56       quantity to pass the validations.
57 
58     Examples
59     --------
60         >>> import astropy.units as u
61         >>> from plasmapy.utils.decorators.converter import angular_freq_to_hz
62         >>>
63         >>> @angular_freq_to_hz
64         ... def foo(x):
65         ...     return x
66         >>>
67         >>> foo(5 * u.rad / u.s, to_hz=True)
68         <Quantity 0.79577472 Hz>
69         >>>
70         >>> foo(-1 * u.rad / u.s, to_hz=True)
71         <Quantity -0.15915494 Hz>
72 
73     Decoration also works with methods
74 
75         >>> class Foo:
76         ...     def __init__(self, x):
77         ...         self.x = x
78         ...
79         ...     @angular_freq_to_hz
80         ...     def bar(self):
81         ...         return self.x
82         >>>
83         >>> foo = Foo(0.5 * u.rad / u.s)
84         >>> foo.bar(to_hz=True)
85         <Quantity 0.07957747 Hz>
86 
87     """
88     # raise exception if fn uses the 'to_hz' kwarg
89     sig = inspect.signature(fn)
90     if "to_hz" in sig.parameters:
91         raise ValueError(
92             f"Wrapped function '{fn.__name__}' can not use keyword 'to_hz'."
93             f" Keyword reserved for decorator functionality."
94         )
95 
96     # make new signature for fn
97     new_params = sig.parameters.copy()
98     new_params["to_hz"] = inspect.Parameter(
99         "to_hz", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=False
100     )
101     new_sig = inspect.Signature(
102         parameters=new_params.values(), return_annotation=sig.return_annotation
103     )
104     fn.__signature__ = new_sig
105 
106     @preserve_signature
107     @functools.wraps(fn)
108     def wrapper(*args, to_hz=False, **kwargs):
109         _result = fn(*args, **kwargs)
110         if to_hz:
111             return _result.to(u.Hz, equivalencies=[(u.cy / u.s, u.Hz)])
112         return _result
113 
114     added_doc_bit = """
115     Other Parameters
116     ----------------
117     to_hz: bool
118         Set `True` to to convert function output from angular frequency to Hz
119     """
120     if wrapper.__doc__ is not None:
121         wrapper.__doc__ += added_doc_bit
122     else:
123         wrapper.__doc__ = added_doc_bit
124 
125     return wrapper
126
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/plasmapy/utils/decorators/converter.py b/plasmapy/utils/decorators/converter.py
--- a/plasmapy/utils/decorators/converter.py
+++ b/plasmapy/utils/decorators/converter.py
@@ -3,10 +3,8 @@
 __all__ = ["angular_freq_to_hz"]
 
 import astropy.units as u
-import functools
 import inspect
-
-from plasmapy.utils.decorators.helpers import preserve_signature
+import wrapt
 
 
 def angular_freq_to_hz(fn):
@@ -85,7 +83,6 @@
         <Quantity 0.07957747 Hz>
 
     """
-    # raise exception if fn uses the 'to_hz' kwarg
     sig = inspect.signature(fn)
     if "to_hz" in sig.parameters:
         raise ValueError(
@@ -94,32 +91,45 @@
         )
 
     # make new signature for fn
-    new_params = sig.parameters.copy()
-    new_params["to_hz"] = inspect.Parameter(
-        "to_hz", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=False
+    new_params = []
+    var_keyword_param = None
+    for param in sig.parameters.values():
+        if param.kind == param.VAR_KEYWORD:
+            var_keyword_param = param
+        else:
+            new_params.append(param)
+
+    new_params.append(
+        inspect.Parameter("to_hz", inspect.Parameter.KEYWORD_ONLY, default=False)
     )
+
+    if var_keyword_param:
+        new_params.append(var_keyword_param)
+
     new_sig = inspect.Signature(
-        parameters=new_params.values(), return_annotation=sig.return_annotation
+        parameters=new_params, return_annotation=sig.return_annotation
     )
     fn.__signature__ = new_sig
 
-    @preserve_signature
-    @functools.wraps(fn)
-    def wrapper(*args, to_hz=False, **kwargs):
+    @wrapt.decorator
+    def wrapper(fn, instance, args, kwargs):  # noqa: ARG001
+        to_hz = kwargs.pop("to_hz", False)
         _result = fn(*args, **kwargs)
         if to_hz:
             return _result.to(u.Hz, equivalencies=[(u.cy / u.s, u.Hz)])
         return _result
 
+    fn = wrapper(fn)
+
     added_doc_bit = """
     Other Parameters
     ----------------
     to_hz: bool
-        Set `True` to to convert function output from angular frequency to Hz
+        Set `True` to convert function output from angular frequency to Hz
     """
-    if wrapper.__doc__ is not None:
-        wrapper.__doc__ += added_doc_bit
+    if fn.__doc__ is not None:
+        fn.__doc__ += added_doc_bit
     else:
-        wrapper.__doc__ = added_doc_bit
+        fn.__doc__ = added_doc_bit
 
-    return wrapper
+    return fn

{"golden_diff": "diff --git a/plasmapy/utils/decorators/converter.py b/plasmapy/utils/decorators/converter.py\n--- a/plasmapy/utils/decorators/converter.py\n+++ b/plasmapy/utils/decorators/converter.py\n@@ -3,10 +3,8 @@\n __all__ = [\"angular_freq_to_hz\"]\n \n import astropy.units as u\n-import functools\n import inspect\n-\n-from plasmapy.utils.decorators.helpers import preserve_signature\n+import wrapt\n \n \n def angular_freq_to_hz(fn):\n@@ -85,7 +83,6 @@\n         <Quantity 0.07957747 Hz>\n \n     \"\"\"\n-    # raise exception if fn uses the 'to_hz' kwarg\n     sig = inspect.signature(fn)\n     if \"to_hz\" in sig.parameters:\n         raise ValueError(\n@@ -94,32 +91,45 @@\n         )\n \n     # make new signature for fn\n-    new_params = sig.parameters.copy()\n-    new_params[\"to_hz\"] = inspect.Parameter(\n-        \"to_hz\", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=False\n+    new_params = []\n+    var_keyword_param = None\n+    for param in sig.parameters.values():\n+        if param.kind == param.VAR_KEYWORD:\n+            var_keyword_param = param\n+        else:\n+            new_params.append(param)\n+\n+    new_params.append(\n+        inspect.Parameter(\"to_hz\", inspect.Parameter.KEYWORD_ONLY, default=False)\n     )\n+\n+    if var_keyword_param:\n+        new_params.append(var_keyword_param)\n+\n     new_sig = inspect.Signature(\n-        parameters=new_params.values(), return_annotation=sig.return_annotation\n+        parameters=new_params, return_annotation=sig.return_annotation\n     )\n     fn.__signature__ = new_sig\n \n-    @preserve_signature\n-    @functools.wraps(fn)\n-    def wrapper(*args, to_hz=False, **kwargs):\n+    @wrapt.decorator\n+    def wrapper(fn, instance, args, kwargs):  # noqa: ARG001\n+        to_hz = kwargs.pop(\"to_hz\", False)\n         _result = fn(*args, **kwargs)\n         if to_hz:\n             return _result.to(u.Hz, equivalencies=[(u.cy / u.s, u.Hz)])\n         return _result\n \n+    fn = wrapper(fn)\n+\n     added_doc_bit = \"\"\"\n     Other Parameters\n     ----------------\n     to_hz: bool\n-        Set `True` to to convert function output from angular frequency to Hz\n+        Set `True` to convert function output from angular frequency to Hz\n     \"\"\"\n-    if wrapper.__doc__ is not None:\n-        wrapper.__doc__ += added_doc_bit\n+    if fn.__doc__ is not None:\n+        fn.__doc__ += added_doc_bit\n     else:\n-        wrapper.__doc__ = added_doc_bit\n+        fn.__doc__ = added_doc_bit\n \n-    return wrapper\n+    return fn\n", "issue": "Incompatibility between `@angular_freq_to_hz` and var-keyword arguments\n### Bug description\r\n\r\nWhile trying to decorate `gyrofrequency` with `@particle_input` in #2026, I found an issue with `@angular_freq_to_hz`.  It appears that `@angular_freq_to_hz` cannot decorate functions that accept var-keyword arguments.\r\n\r\n### Expected outcome\r\n\r\nWe should be able to use `@angular_freq_to_hz` to decorate functions with var-keyword parameters.\r\n\r\n### Minimal complete verifiable example\r\n\r\nWhen declaring this function:\r\n\r\n```Python\r\nfrom plasmapy.utils.decorators import angular_freq_to_hz\r\n@angular_freq_to_hz\r\ndef f(**kwargs):\r\n    return kwargs\r\n```\r\nI get:\r\n```python\r\n---------------------------------------------------------------------------\r\nValueError                                Traceback (most recent call last)\r\nCell In[41], line 1\r\n----> 1 @angular_freq_to_hz\r\n      2 def f(**kwargs):\r\n      3     return kwargs\r\n\r\nFile ~/Projects/PlasmaPy/plasmapy/utils/decorators/converter.py:101, in angular_freq_to_hz(fn)\r\n     97 new_params = sig.parameters.copy()\r\n     98 new_params[\"to_hz\"] = inspect.Parameter(\r\n     99     \"to_hz\", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=False\r\n    100 )\r\n--> 101 new_sig = inspect.Signature(\r\n    102     parameters=new_params.values(), return_annotation=sig.return_annotation\r\n    103 )\r\n    104 fn.__signature__ = new_sig\r\n    106 @preserve_signature\r\n    107 @functools.wraps(fn)\r\n    108 def wrapper(*args, to_hz=False, **kwargs):\r\n\r\nFile ~/miniconda3/envs/pldev/lib/python3.11/inspect.py:2994, in Signature.__init__(self, parameters, return_annotation, __validate_parameters__)\r\n   2988     msg = (\r\n   2989         'wrong parameter order: {} parameter before {} '\r\n   2990         'parameter'\r\n   2991     )\r\n   2992     msg = msg.format(top_kind.description,\r\n   2993                      kind.description)\r\n-> 2994     raise ValueError(msg)\r\n   2995 elif kind > top_kind:\r\n   2996     kind_defaults = False\r\n\r\nValueError: wrong parameter order: variadic keyword parameter before positional or keyword parameter\r\n```\r\n\r\n\r\n### Package versions\r\n\r\nDevelopment branch \r\n\r\n### Additional context\r\n\r\nThis is medium priority to address since it's blocking #2026 and possibly also #2022.\n", "before_files": [{"content": "\"\"\"Decorators to convert units.\"\"\"\n\n__all__ = [\"angular_freq_to_hz\"]\n\nimport astropy.units as u\nimport functools\nimport inspect\n\nfrom plasmapy.utils.decorators.helpers import preserve_signature\n\n\ndef angular_freq_to_hz(fn):\n    \"\"\"\n    A decorator that enables a function to convert its return\n    value from angular frequency (rad/s) to frequency (Hz).\n\n    A kwarg ``to_hz`` is added to the function's signature, with a\n    default value of `False`.  The keyword is also added to the\n    function's docstring under the **\"Other Parameters\"** heading.\n\n    Parameters\n    ----------\n    fn : function\n        The function to be decorated.\n\n    Raises\n    ------\n    ValueError\n        If ``fn`` has already defined a kwarg ``to_hz``.\n\n    Returns\n    -------\n    callable\n        The decorated function.\n\n    Notes\n    -----\n    * If `~plasmapy.utils.decorators.converter.angular_freq_to_hz` is\n      used with decorator\n      :func:`~plasmapy.utils.decorators.validators.validate_quantities`,\n      then `angular_freq_to_hz` should be used inside\n      :func:`~plasmapy.utils.decorators.validators.validate_quantities`\n      but special consideration is needed for setup.  The following is\n      an example of an appropriate setup::\n\n        import astropy.units as u\n        from plasmapy.utils.decorators.converter import angular_freq_to_hz\n        from plasmapy.utils.decorators.validators import validate_quantities\n\n        @validate_quantities(validations_on_return={'units': [u.rad / u.s, u.Hz]})\n        @angular_freq_to_hz\n        def foo(x: u.rad / u.s) -> u.rad / u.s\n            return x\n\n      Adding ``u.Hz`` to the allowed units allows the converted\n      quantity to pass the validations.\n\n    Examples\n    --------\n        >>> import astropy.units as u\n        >>> from plasmapy.utils.decorators.converter import angular_freq_to_hz\n        >>>\n        >>> @angular_freq_to_hz\n        ... def foo(x):\n        ...     return x\n        >>>\n        >>> foo(5 * u.rad / u.s, to_hz=True)\n        <Quantity 0.79577472 Hz>\n        >>>\n        >>> foo(-1 * u.rad / u.s, to_hz=True)\n        <Quantity -0.15915494 Hz>\n\n    Decoration also works with methods\n\n        >>> class Foo:\n        ...     def __init__(self, x):\n        ...         self.x = x\n        ...\n        ...     @angular_freq_to_hz\n        ...     def bar(self):\n        ...         return self.x\n        >>>\n        >>> foo = Foo(0.5 * u.rad / u.s)\n        >>> foo.bar(to_hz=True)\n        <Quantity 0.07957747 Hz>\n\n    \"\"\"\n    # raise exception if fn uses the 'to_hz' kwarg\n    sig = inspect.signature(fn)\n    if \"to_hz\" in sig.parameters:\n        raise ValueError(\n            f\"Wrapped function '{fn.__name__}' can not use keyword 'to_hz'.\"\n            f\" Keyword reserved for decorator functionality.\"\n        )\n\n    # make new signature for fn\n    new_params = sig.parameters.copy()\n    new_params[\"to_hz\"] = inspect.Parameter(\n        \"to_hz\", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=False\n    )\n    new_sig = inspect.Signature(\n        parameters=new_params.values(), return_annotation=sig.return_annotation\n    )\n    fn.__signature__ = new_sig\n\n    @preserve_signature\n    @functools.wraps(fn)\n    def wrapper(*args, to_hz=False, **kwargs):\n        _result = fn(*args, **kwargs)\n        if to_hz:\n            return _result.to(u.Hz, equivalencies=[(u.cy / u.s, u.Hz)])\n        return _result\n\n    added_doc_bit = \"\"\"\n    Other Parameters\n    ----------------\n    to_hz: bool\n        Set `True` to to convert function output from angular frequency to Hz\n    \"\"\"\n    if wrapper.__doc__ is not None:\n        wrapper.__doc__ += added_doc_bit\n    else:\n        wrapper.__doc__ = added_doc_bit\n\n    return wrapper\n", "path": "plasmapy/utils/decorators/converter.py"}], "after_files": [{"content": "\"\"\"Decorators to convert units.\"\"\"\n\n__all__ = [\"angular_freq_to_hz\"]\n\nimport astropy.units as u\nimport inspect\nimport wrapt\n\n\ndef angular_freq_to_hz(fn):\n    \"\"\"\n    A decorator that enables a function to convert its return\n    value from angular frequency (rad/s) to frequency (Hz).\n\n    A kwarg ``to_hz`` is added to the function's signature, with a\n    default value of `False`.  The keyword is also added to the\n    function's docstring under the **\"Other Parameters\"** heading.\n\n    Parameters\n    ----------\n    fn : function\n        The function to be decorated.\n\n    Raises\n    ------\n    ValueError\n        If ``fn`` has already defined a kwarg ``to_hz``.\n\n    Returns\n    -------\n    callable\n        The decorated function.\n\n    Notes\n    -----\n    * If `~plasmapy.utils.decorators.converter.angular_freq_to_hz` is\n      used with decorator\n      :func:`~plasmapy.utils.decorators.validators.validate_quantities`,\n      then `angular_freq_to_hz` should be used inside\n      :func:`~plasmapy.utils.decorators.validators.validate_quantities`\n      but special consideration is needed for setup.  The following is\n      an example of an appropriate setup::\n\n        import astropy.units as u\n        from plasmapy.utils.decorators.converter import angular_freq_to_hz\n        from plasmapy.utils.decorators.validators import validate_quantities\n\n        @validate_quantities(validations_on_return={'units': [u.rad / u.s, u.Hz]})\n        @angular_freq_to_hz\n        def foo(x: u.rad / u.s) -> u.rad / u.s\n            return x\n\n      Adding ``u.Hz`` to the allowed units allows the converted\n      quantity to pass the validations.\n\n    Examples\n    --------\n        >>> import astropy.units as u\n        >>> from plasmapy.utils.decorators.converter import angular_freq_to_hz\n        >>>\n        >>> @angular_freq_to_hz\n        ... def foo(x):\n        ...     return x\n        >>>\n        >>> foo(5 * u.rad / u.s, to_hz=True)\n        <Quantity 0.79577472 Hz>\n        >>>\n        >>> foo(-1 * u.rad / u.s, to_hz=True)\n        <Quantity -0.15915494 Hz>\n\n    Decoration also works with methods\n\n        >>> class Foo:\n        ...     def __init__(self, x):\n        ...         self.x = x\n        ...\n        ...     @angular_freq_to_hz\n        ...     def bar(self):\n        ...         return self.x\n        >>>\n        >>> foo = Foo(0.5 * u.rad / u.s)\n        >>> foo.bar(to_hz=True)\n        <Quantity 0.07957747 Hz>\n\n    \"\"\"\n    sig = inspect.signature(fn)\n    if \"to_hz\" in sig.parameters:\n        raise ValueError(\n            f\"Wrapped function '{fn.__name__}' can not use keyword 'to_hz'.\"\n            f\" Keyword reserved for decorator functionality.\"\n        )\n\n    # make new signature for fn\n    new_params = []\n    var_keyword_param = None\n    for param in sig.parameters.values():\n        if param.kind == param.VAR_KEYWORD:\n            var_keyword_param = param\n        else:\n            new_params.append(param)\n\n    new_params.append(\n        inspect.Parameter(\"to_hz\", inspect.Parameter.KEYWORD_ONLY, default=False)\n    )\n\n    if var_keyword_param:\n        new_params.append(var_keyword_param)\n\n    new_sig = inspect.Signature(\n        parameters=new_params, return_annotation=sig.return_annotation\n    )\n    fn.__signature__ = new_sig\n\n    @wrapt.decorator\n    def wrapper(fn, instance, args, kwargs):  # noqa: ARG001\n        to_hz = kwargs.pop(\"to_hz\", False)\n        _result = fn(*args, **kwargs)\n        if to_hz:\n            return _result.to(u.Hz, equivalencies=[(u.cy / u.s, u.Hz)])\n        return _result\n\n    fn = wrapper(fn)\n\n    added_doc_bit = \"\"\"\n    Other Parameters\n    ----------------\n    to_hz: bool\n        Set `True` to convert function output from angular frequency to Hz\n    \"\"\"\n    if fn.__doc__ is not None:\n        fn.__doc__ += added_doc_bit\n    else:\n        fn.__doc__ = added_doc_bit\n\n    return fn\n", "path": "plasmapy/utils/decorators/converter.py"}]}