We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow not using parens on cocotb.test decorator
In many (if not the majority) of cases, users don't need to pass arguments to the test decorator. In this case it would be nice if they didn't need to "call" the decorator.

```python
@cocotb.test  # no call here
async def test_stuff(dut):
    ...
```

Standard library decorator support this (like `lru_cache`), so there is precedence to support this as well.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cocotb/decorators.py`
Content:
```
1 # Copyright (c) 2013 Potential Ventures Ltd
2 # Copyright (c) 2013 SolarFlare Communications Inc
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
7 #     * Redistributions of source code must retain the above copyright
8 #       notice, this list of conditions and the following disclaimer.
9 #     * Redistributions in binary form must reproduce the above copyright
10 #       notice, this list of conditions and the following disclaimer in the
11 #       documentation and/or other materials provided with the distribution.
12 #     * Neither the name of Potential Ventures Ltd,
13 #       SolarFlare Communications Inc nor the
14 #       names of its contributors may be used to endorse or promote products
15 #       derived from this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 # DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY
21 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 import functools
29 import sys
30 import typing
31 import warnings
32 
33 import cocotb
34 import cocotb.triggers
35 from cocotb.log import SimLog
36 from cocotb.task import Task as _Task  # noqa: F401
37 from cocotb.task import _RunningCoroutine, _RunningTest
38 from cocotb.utils import lazy_property
39 
40 
41 def public(f):
42     """Use a decorator to avoid retyping function/class names.
43 
44     * Based on an idea by Duncan Booth:
45     http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a
46     * Improved via a suggestion by Dave Angel:
47     http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1
48     """
49     all = sys.modules[f.__module__].__dict__.setdefault("__all__", [])
50     if f.__name__ not in all:  # Prevent duplicates if run from an IDE.
51         all.append(f.__name__)
52     return f
53 
54 
55 public(public)  # Emulate decorating ourself
56 
57 
58 class coroutine:
59     """Decorator class that allows us to provide common coroutine mechanisms:
60 
61     ``log`` methods will log to ``cocotb.coroutine.name``.
62 
63     :meth:`~cocotb.task.Task.join` method returns an event which will fire when the coroutine exits.
64 
65     Used as ``@cocotb.coroutine``.
66     """
67 
68     def __init__(self, func):
69         self._func = func
70         functools.update_wrapper(self, func)
71 
72     @lazy_property
73     def log(self):
74         return SimLog(f"cocotb.coroutine.{self._func.__qualname__}.{id(self)}")
75 
76     def __call__(self, *args, **kwargs):
77         return _RunningCoroutine(self._func(*args, **kwargs), self)
78 
79     def __get__(self, obj, owner=None):
80         """Permit the decorator to be used on class methods
81         and standalone functions"""
82         return type(self)(self._func.__get__(obj, owner))
83 
84     def __iter__(self):
85         return self
86 
87     def __str__(self):
88         return str(self._func.__qualname__)
89 
90 
91 @public
92 class function:
93     """Decorator class that allows a function to block.
94 
95     This allows a coroutine that consumes simulation time
96     to be called by a thread started with :class:`cocotb.external`;
97     in other words, to internally block while externally
98     appear to yield.
99     """
100 
101     def __init__(self, func):
102         self._coro = cocotb.coroutine(func)
103 
104     @lazy_property
105     def log(self):
106         return SimLog(f"cocotb.function.{self._coro.__qualname__}.{id(self)}")
107 
108     def __call__(self, *args, **kwargs):
109         return cocotb.scheduler._queue_function(self._coro(*args, **kwargs))
110 
111     def __get__(self, obj, owner=None):
112         """Permit the decorator to be used on class methods
113         and standalone functions"""
114         return type(self)(self._coro._func.__get__(obj, owner))
115 
116 
117 @public
118 class external:
119     """Decorator to apply to an external function to enable calling from cocotb.
120 
121     This turns a normal function that isn't a coroutine into a blocking coroutine.
122     Currently, this creates a new execution thread for each function that is
123     called.
124     Scope for this to be streamlined to a queue in future.
125     """
126 
127     def __init__(self, func):
128         self._func = func
129         self._log = SimLog(f"cocotb.external.{self._func.__qualname__}.{id(self)}")
130 
131     def __call__(self, *args, **kwargs):
132         return cocotb.scheduler._run_in_executor(self._func, *args, **kwargs)
133 
134     def __get__(self, obj, owner=None):
135         """Permit the decorator to be used on class methods
136         and standalone functions"""
137         return type(self)(self._func.__get__(obj, owner))
138 
139 
140 class _decorator_helper(type):
141     """
142     Metaclass that allows a type to be constructed using decorator syntax,
143     passing the decorated function as the first argument.
144 
145     So:
146 
147         @MyClass(construction, args='go here')
148         def this_is_passed_as_f(...):
149             pass
150 
151     ends up calling
152 
153         MyClass.__init__(this_is_passed_as_f, construction, args='go here')
154     """
155 
156     def __call__(cls, *args, **kwargs):
157         def decorator(f):
158             # fall back to the normal way of constructing an object, now that
159             # we have all the arguments
160             return type.__call__(cls, f, *args, **kwargs)
161 
162         return decorator
163 
164 
165 @public
166 class test(coroutine, metaclass=_decorator_helper):
167     """
168     Decorator to mark a Callable which returns a Coroutine as a test.
169 
170     The test decorator provides a test timeout, and allows us to mark tests as skipped
171     or expecting errors or failures.
172     Tests are evaluated in the order they are defined in a test module.
173 
174     Used as ``@cocotb.test(...)``.
175 
176     Args:
177         timeout_time (numbers.Real or decimal.Decimal, optional):
178             Simulation time duration before timeout occurs.
179 
180             .. versionadded:: 1.3
181 
182             .. note::
183                 Test timeout is intended for protection against deadlock.
184                 Users should use :class:`~cocotb.triggers.with_timeout` if they require a
185                 more general-purpose timeout mechanism.
186 
187         timeout_unit (str, optional):
188             Units of timeout_time, accepts any units that :class:`~cocotb.triggers.Timer` does.
189 
190             .. versionadded:: 1.3
191 
192             .. deprecated:: 1.5
193                 Using ``None`` as the *timeout_unit* argument is deprecated, use ``'step'`` instead.
194 
195         expect_fail (bool, optional):
196             If ``True`` and the test fails a functional check via an ``assert`` statement, :class:`pytest.raises`,
197             :class:`pytest.warns`, or :class:`pytest.deprecated_call` the test is considered to have passed.
198             If ``True`` and the test passes successfully, the test is considered to have failed.
199 
200         expect_error (exception type or tuple of exception types, optional):
201             Mark the result as a pass only if one of the exception types is raised in the test.
202             This is primarily for cocotb internal regression use for when a simulator error is expected.
203 
204             Users are encouraged to use the following idiom instead::
205 
206                 @cocotb.test()
207                 async def my_test(dut):
208                     try:
209                         await thing_that_should_fail()
210                     except ExceptionIExpect:
211                         pass
212                     else:
213                         assert False, "Exception did not occur"
214 
215             .. versionchanged:: 1.3
216                 Specific exception types can be expected
217 
218             .. deprecated:: 1.5
219                 Passing a :class:`bool` value is now deprecated.
220                 Pass a specific :class:`Exception` or a tuple of Exceptions instead.
221 
222         skip (bool, optional):
223             Don't execute this test as part of the regression. Test can still be run
224             manually by setting :make:var:`TESTCASE`.
225 
226         stage (int)
227             Order tests logically into stages, where multiple tests can share a stage.
228             Defaults to 0.
229     """
230 
231     _id_count = 0  # used by the RegressionManager to sort tests in definition order
232 
233     def __init__(
234         self,
235         f,
236         timeout_time=None,
237         timeout_unit="step",
238         expect_fail=False,
239         expect_error=(),
240         skip=False,
241         stage=0,
242     ):
243         if timeout_unit is None:
244             warnings.warn(
245                 'Using timeout_unit=None is deprecated, use timeout_unit="step" instead.',
246                 DeprecationWarning,
247                 stacklevel=2,
248             )
249             timeout_unit = "step"  # don't propagate deprecated value
250         self._id = self._id_count
251         type(self)._id_count += 1
252 
253         if timeout_time is not None:
254             co = coroutine(f)
255 
256             @functools.wraps(f)
257             async def f(*args, **kwargs):
258                 running_co = co(*args, **kwargs)
259 
260                 try:
261                     res = await cocotb.triggers.with_timeout(
262                         running_co, self.timeout_time, self.timeout_unit
263                     )
264                 except cocotb.result.SimTimeoutError:
265                     running_co.kill()
266                     raise
267                 else:
268                     return res
269 
270         super().__init__(f)
271 
272         self.timeout_time = timeout_time
273         self.timeout_unit = timeout_unit
274         self.expect_fail = expect_fail
275         if isinstance(expect_error, bool):
276             warnings.warn(
277                 "Passing bool values to `except_error` option of `cocotb.test` is deprecated. "
278                 "Pass a specific Exception type instead",
279                 DeprecationWarning,
280                 stacklevel=2,
281             )
282         if expect_error is True:
283             expect_error = (BaseException,)
284         elif expect_error is False:
285             expect_error = ()
286         self.expect_error = expect_error
287         self.skip = skip
288         self.stage = stage
289         self.im_test = True  # For auto-regressions
290         self.name = self._func.__name__
291 
292     def __call__(self, *args, **kwargs):
293         inst = self._func(*args, **kwargs)
294         coro = _RunningTest(inst, self)
295         return coro
296 
297 
298 if sys.version_info < (3, 7):
299     Task = _Task
300     RunningTask = _Task
301     RunningCoroutine = _RunningCoroutine
302     RunningTest = _RunningTest
303 else:
304 
305     def __getattr__(attr: str) -> typing.Any:
306         if attr in ("Task", "RunningTask"):
307             warnings.warn(
308                 f"The class {attr} has been renamed to cocotb.task.Task.",
309                 DeprecationWarning,
310                 stacklevel=2,
311             )
312             attr = "_Task"
313         elif attr in ("RunningCoroutine", "RunningTest"):
314             warnings.warn(
315                 f"The class {attr} is now private. Update all uses to the parent class cocotb.task.Task.",
316                 DeprecationWarning,
317                 stacklevel=2,
318             )
319             attr = f"_{attr}"
320         try:
321             return globals()[attr]
322         except KeyError:
323             raise AttributeError(
324                 f"module {__name__!r} has no attribute {attr!r}"
325             ) from None
326
```
--- 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/cocotb/decorators.py b/cocotb/decorators.py
--- a/cocotb/decorators.py
+++ b/cocotb/decorators.py
@@ -140,7 +140,8 @@
 class _decorator_helper(type):
     """
     Metaclass that allows a type to be constructed using decorator syntax,
-    passing the decorated function as the first argument.
+    passing the decorated function as the first argument. Supports
+    construction with or without having the type called.
 
     So:
 
@@ -154,6 +155,11 @@
     """
 
     def __call__(cls, *args, **kwargs):
+        if len(args) == 1 and callable(args[0]):  # case without parenthesis
+            f = args[0]
+            return type.__call__(cls, f, **kwargs)
+
+        # case with parenthesis
         def decorator(f):
             # fall back to the normal way of constructing an object, now that
             # we have all the arguments

{"golden_diff": "diff --git a/cocotb/decorators.py b/cocotb/decorators.py\n--- a/cocotb/decorators.py\n+++ b/cocotb/decorators.py\n@@ -140,7 +140,8 @@\n class _decorator_helper(type):\n     \"\"\"\n     Metaclass that allows a type to be constructed using decorator syntax,\n-    passing the decorated function as the first argument.\n+    passing the decorated function as the first argument. Supports\n+    construction with or without having the type called.\n \n     So:\n \n@@ -154,6 +155,11 @@\n     \"\"\"\n \n     def __call__(cls, *args, **kwargs):\n+        if len(args) == 1 and callable(args[0]):  # case without parenthesis\n+            f = args[0]\n+            return type.__call__(cls, f, **kwargs)\n+\n+        # case with parenthesis\n         def decorator(f):\n             # fall back to the normal way of constructing an object, now that\n             # we have all the arguments\n", "issue": "Allow not using parens on cocotb.test decorator\nIn many (if not the majority) of cases, users don't need to pass arguments to the test decorator. In this case it would be nice if they didn't need to \"call\" the decorator.\r\n\r\n```python\r\n@cocotb.test  # no call here\r\nasync def test_stuff(dut):\r\n    ...\r\n```\r\n\r\nStandard library decorator support this (like `lru_cache`), so there is precedence to support this as well.\n", "before_files": [{"content": "# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#     * Redistributions of source code must retain the above copyright\n#       notice, this list of conditions and the following disclaimer.\n#     * Redistributions in binary form must reproduce the above copyright\n#       notice, this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n#     * Neither the name of Potential Ventures Ltd,\n#       SolarFlare Communications Inc nor the\n#       names of its contributors may be used to endorse or promote products\n#       derived from this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport functools\nimport sys\nimport typing\nimport warnings\n\nimport cocotb\nimport cocotb.triggers\nfrom cocotb.log import SimLog\nfrom cocotb.task import Task as _Task  # noqa: F401\nfrom cocotb.task import _RunningCoroutine, _RunningTest\nfrom cocotb.utils import lazy_property\n\n\ndef public(f):\n    \"\"\"Use a decorator to avoid retyping function/class names.\n\n    * Based on an idea by Duncan Booth:\n    http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a\n    * Improved via a suggestion by Dave Angel:\n    http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1\n    \"\"\"\n    all = sys.modules[f.__module__].__dict__.setdefault(\"__all__\", [])\n    if f.__name__ not in all:  # Prevent duplicates if run from an IDE.\n        all.append(f.__name__)\n    return f\n\n\npublic(public)  # Emulate decorating ourself\n\n\nclass coroutine:\n    \"\"\"Decorator class that allows us to provide common coroutine mechanisms:\n\n    ``log`` methods will log to ``cocotb.coroutine.name``.\n\n    :meth:`~cocotb.task.Task.join` method returns an event which will fire when the coroutine exits.\n\n    Used as ``@cocotb.coroutine``.\n    \"\"\"\n\n    def __init__(self, func):\n        self._func = func\n        functools.update_wrapper(self, func)\n\n    @lazy_property\n    def log(self):\n        return SimLog(f\"cocotb.coroutine.{self._func.__qualname__}.{id(self)}\")\n\n    def __call__(self, *args, **kwargs):\n        return _RunningCoroutine(self._func(*args, **kwargs), self)\n\n    def __get__(self, obj, owner=None):\n        \"\"\"Permit the decorator to be used on class methods\n        and standalone functions\"\"\"\n        return type(self)(self._func.__get__(obj, owner))\n\n    def __iter__(self):\n        return self\n\n    def __str__(self):\n        return str(self._func.__qualname__)\n\n\n@public\nclass function:\n    \"\"\"Decorator class that allows a function to block.\n\n    This allows a coroutine that consumes simulation time\n    to be called by a thread started with :class:`cocotb.external`;\n    in other words, to internally block while externally\n    appear to yield.\n    \"\"\"\n\n    def __init__(self, func):\n        self._coro = cocotb.coroutine(func)\n\n    @lazy_property\n    def log(self):\n        return SimLog(f\"cocotb.function.{self._coro.__qualname__}.{id(self)}\")\n\n    def __call__(self, *args, **kwargs):\n        return cocotb.scheduler._queue_function(self._coro(*args, **kwargs))\n\n    def __get__(self, obj, owner=None):\n        \"\"\"Permit the decorator to be used on class methods\n        and standalone functions\"\"\"\n        return type(self)(self._coro._func.__get__(obj, owner))\n\n\n@public\nclass external:\n    \"\"\"Decorator to apply to an external function to enable calling from cocotb.\n\n    This turns a normal function that isn't a coroutine into a blocking coroutine.\n    Currently, this creates a new execution thread for each function that is\n    called.\n    Scope for this to be streamlined to a queue in future.\n    \"\"\"\n\n    def __init__(self, func):\n        self._func = func\n        self._log = SimLog(f\"cocotb.external.{self._func.__qualname__}.{id(self)}\")\n\n    def __call__(self, *args, **kwargs):\n        return cocotb.scheduler._run_in_executor(self._func, *args, **kwargs)\n\n    def __get__(self, obj, owner=None):\n        \"\"\"Permit the decorator to be used on class methods\n        and standalone functions\"\"\"\n        return type(self)(self._func.__get__(obj, owner))\n\n\nclass _decorator_helper(type):\n    \"\"\"\n    Metaclass that allows a type to be constructed using decorator syntax,\n    passing the decorated function as the first argument.\n\n    So:\n\n        @MyClass(construction, args='go here')\n        def this_is_passed_as_f(...):\n            pass\n\n    ends up calling\n\n        MyClass.__init__(this_is_passed_as_f, construction, args='go here')\n    \"\"\"\n\n    def __call__(cls, *args, **kwargs):\n        def decorator(f):\n            # fall back to the normal way of constructing an object, now that\n            # we have all the arguments\n            return type.__call__(cls, f, *args, **kwargs)\n\n        return decorator\n\n\n@public\nclass test(coroutine, metaclass=_decorator_helper):\n    \"\"\"\n    Decorator to mark a Callable which returns a Coroutine as a test.\n\n    The test decorator provides a test timeout, and allows us to mark tests as skipped\n    or expecting errors or failures.\n    Tests are evaluated in the order they are defined in a test module.\n\n    Used as ``@cocotb.test(...)``.\n\n    Args:\n        timeout_time (numbers.Real or decimal.Decimal, optional):\n            Simulation time duration before timeout occurs.\n\n            .. versionadded:: 1.3\n\n            .. note::\n                Test timeout is intended for protection against deadlock.\n                Users should use :class:`~cocotb.triggers.with_timeout` if they require a\n                more general-purpose timeout mechanism.\n\n        timeout_unit (str, optional):\n            Units of timeout_time, accepts any units that :class:`~cocotb.triggers.Timer` does.\n\n            .. versionadded:: 1.3\n\n            .. deprecated:: 1.5\n                Using ``None`` as the *timeout_unit* argument is deprecated, use ``'step'`` instead.\n\n        expect_fail (bool, optional):\n            If ``True`` and the test fails a functional check via an ``assert`` statement, :class:`pytest.raises`,\n            :class:`pytest.warns`, or :class:`pytest.deprecated_call` the test is considered to have passed.\n            If ``True`` and the test passes successfully, the test is considered to have failed.\n\n        expect_error (exception type or tuple of exception types, optional):\n            Mark the result as a pass only if one of the exception types is raised in the test.\n            This is primarily for cocotb internal regression use for when a simulator error is expected.\n\n            Users are encouraged to use the following idiom instead::\n\n                @cocotb.test()\n                async def my_test(dut):\n                    try:\n                        await thing_that_should_fail()\n                    except ExceptionIExpect:\n                        pass\n                    else:\n                        assert False, \"Exception did not occur\"\n\n            .. versionchanged:: 1.3\n                Specific exception types can be expected\n\n            .. deprecated:: 1.5\n                Passing a :class:`bool` value is now deprecated.\n                Pass a specific :class:`Exception` or a tuple of Exceptions instead.\n\n        skip (bool, optional):\n            Don't execute this test as part of the regression. Test can still be run\n            manually by setting :make:var:`TESTCASE`.\n\n        stage (int)\n            Order tests logically into stages, where multiple tests can share a stage.\n            Defaults to 0.\n    \"\"\"\n\n    _id_count = 0  # used by the RegressionManager to sort tests in definition order\n\n    def __init__(\n        self,\n        f,\n        timeout_time=None,\n        timeout_unit=\"step\",\n        expect_fail=False,\n        expect_error=(),\n        skip=False,\n        stage=0,\n    ):\n        if timeout_unit is None:\n            warnings.warn(\n                'Using timeout_unit=None is deprecated, use timeout_unit=\"step\" instead.',\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            timeout_unit = \"step\"  # don't propagate deprecated value\n        self._id = self._id_count\n        type(self)._id_count += 1\n\n        if timeout_time is not None:\n            co = coroutine(f)\n\n            @functools.wraps(f)\n            async def f(*args, **kwargs):\n                running_co = co(*args, **kwargs)\n\n                try:\n                    res = await cocotb.triggers.with_timeout(\n                        running_co, self.timeout_time, self.timeout_unit\n                    )\n                except cocotb.result.SimTimeoutError:\n                    running_co.kill()\n                    raise\n                else:\n                    return res\n\n        super().__init__(f)\n\n        self.timeout_time = timeout_time\n        self.timeout_unit = timeout_unit\n        self.expect_fail = expect_fail\n        if isinstance(expect_error, bool):\n            warnings.warn(\n                \"Passing bool values to `except_error` option of `cocotb.test` is deprecated. \"\n                \"Pass a specific Exception type instead\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n        if expect_error is True:\n            expect_error = (BaseException,)\n        elif expect_error is False:\n            expect_error = ()\n        self.expect_error = expect_error\n        self.skip = skip\n        self.stage = stage\n        self.im_test = True  # For auto-regressions\n        self.name = self._func.__name__\n\n    def __call__(self, *args, **kwargs):\n        inst = self._func(*args, **kwargs)\n        coro = _RunningTest(inst, self)\n        return coro\n\n\nif sys.version_info < (3, 7):\n    Task = _Task\n    RunningTask = _Task\n    RunningCoroutine = _RunningCoroutine\n    RunningTest = _RunningTest\nelse:\n\n    def __getattr__(attr: str) -> typing.Any:\n        if attr in (\"Task\", \"RunningTask\"):\n            warnings.warn(\n                f\"The class {attr} has been renamed to cocotb.task.Task.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            attr = \"_Task\"\n        elif attr in (\"RunningCoroutine\", \"RunningTest\"):\n            warnings.warn(\n                f\"The class {attr} is now private. Update all uses to the parent class cocotb.task.Task.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            attr = f\"_{attr}\"\n        try:\n            return globals()[attr]\n        except KeyError:\n            raise AttributeError(\n                f\"module {__name__!r} has no attribute {attr!r}\"\n            ) from None\n", "path": "cocotb/decorators.py"}], "after_files": [{"content": "# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#     * Redistributions of source code must retain the above copyright\n#       notice, this list of conditions and the following disclaimer.\n#     * Redistributions in binary form must reproduce the above copyright\n#       notice, this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n#     * Neither the name of Potential Ventures Ltd,\n#       SolarFlare Communications Inc nor the\n#       names of its contributors may be used to endorse or promote products\n#       derived from this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport functools\nimport sys\nimport typing\nimport warnings\n\nimport cocotb\nimport cocotb.triggers\nfrom cocotb.log import SimLog\nfrom cocotb.task import Task as _Task  # noqa: F401\nfrom cocotb.task import _RunningCoroutine, _RunningTest\nfrom cocotb.utils import lazy_property\n\n\ndef public(f):\n    \"\"\"Use a decorator to avoid retyping function/class names.\n\n    * Based on an idea by Duncan Booth:\n    http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a\n    * Improved via a suggestion by Dave Angel:\n    http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1\n    \"\"\"\n    all = sys.modules[f.__module__].__dict__.setdefault(\"__all__\", [])\n    if f.__name__ not in all:  # Prevent duplicates if run from an IDE.\n        all.append(f.__name__)\n    return f\n\n\npublic(public)  # Emulate decorating ourself\n\n\nclass coroutine:\n    \"\"\"Decorator class that allows us to provide common coroutine mechanisms:\n\n    ``log`` methods will log to ``cocotb.coroutine.name``.\n\n    :meth:`~cocotb.task.Task.join` method returns an event which will fire when the coroutine exits.\n\n    Used as ``@cocotb.coroutine``.\n    \"\"\"\n\n    def __init__(self, func):\n        self._func = func\n        functools.update_wrapper(self, func)\n\n    @lazy_property\n    def log(self):\n        return SimLog(f\"cocotb.coroutine.{self._func.__qualname__}.{id(self)}\")\n\n    def __call__(self, *args, **kwargs):\n        return _RunningCoroutine(self._func(*args, **kwargs), self)\n\n    def __get__(self, obj, owner=None):\n        \"\"\"Permit the decorator to be used on class methods\n        and standalone functions\"\"\"\n        return type(self)(self._func.__get__(obj, owner))\n\n    def __iter__(self):\n        return self\n\n    def __str__(self):\n        return str(self._func.__qualname__)\n\n\n@public\nclass function:\n    \"\"\"Decorator class that allows a function to block.\n\n    This allows a coroutine that consumes simulation time\n    to be called by a thread started with :class:`cocotb.external`;\n    in other words, to internally block while externally\n    appear to yield.\n    \"\"\"\n\n    def __init__(self, func):\n        self._coro = cocotb.coroutine(func)\n\n    @lazy_property\n    def log(self):\n        return SimLog(f\"cocotb.function.{self._coro.__qualname__}.{id(self)}\")\n\n    def __call__(self, *args, **kwargs):\n        return cocotb.scheduler._queue_function(self._coro(*args, **kwargs))\n\n    def __get__(self, obj, owner=None):\n        \"\"\"Permit the decorator to be used on class methods\n        and standalone functions\"\"\"\n        return type(self)(self._coro._func.__get__(obj, owner))\n\n\n@public\nclass external:\n    \"\"\"Decorator to apply to an external function to enable calling from cocotb.\n\n    This turns a normal function that isn't a coroutine into a blocking coroutine.\n    Currently, this creates a new execution thread for each function that is\n    called.\n    Scope for this to be streamlined to a queue in future.\n    \"\"\"\n\n    def __init__(self, func):\n        self._func = func\n        self._log = SimLog(f\"cocotb.external.{self._func.__qualname__}.{id(self)}\")\n\n    def __call__(self, *args, **kwargs):\n        return cocotb.scheduler._run_in_executor(self._func, *args, **kwargs)\n\n    def __get__(self, obj, owner=None):\n        \"\"\"Permit the decorator to be used on class methods\n        and standalone functions\"\"\"\n        return type(self)(self._func.__get__(obj, owner))\n\n\nclass _decorator_helper(type):\n    \"\"\"\n    Metaclass that allows a type to be constructed using decorator syntax,\n    passing the decorated function as the first argument. Supports\n    construction with or without having the type called.\n\n    So:\n\n        @MyClass(construction, args='go here')\n        def this_is_passed_as_f(...):\n            pass\n\n    ends up calling\n\n        MyClass.__init__(this_is_passed_as_f, construction, args='go here')\n    \"\"\"\n\n    def __call__(cls, *args, **kwargs):\n        if len(args) == 1 and callable(args[0]):  # case without parenthesis\n            f = args[0]\n            return type.__call__(cls, f, **kwargs)\n\n        # case with parenthesis\n        def decorator(f):\n            # fall back to the normal way of constructing an object, now that\n            # we have all the arguments\n            return type.__call__(cls, f, *args, **kwargs)\n\n        return decorator\n\n\n@public\nclass test(coroutine, metaclass=_decorator_helper):\n    \"\"\"\n    Decorator to mark a Callable which returns a Coroutine as a test.\n\n    The test decorator provides a test timeout, and allows us to mark tests as skipped\n    or expecting errors or failures.\n    Tests are evaluated in the order they are defined in a test module.\n\n    Used as ``@cocotb.test(...)``.\n\n    Args:\n        timeout_time (numbers.Real or decimal.Decimal, optional):\n            Simulation time duration before timeout occurs.\n\n            .. versionadded:: 1.3\n\n            .. note::\n                Test timeout is intended for protection against deadlock.\n                Users should use :class:`~cocotb.triggers.with_timeout` if they require a\n                more general-purpose timeout mechanism.\n\n        timeout_unit (str, optional):\n            Units of timeout_time, accepts any units that :class:`~cocotb.triggers.Timer` does.\n\n            .. versionadded:: 1.3\n\n            .. deprecated:: 1.5\n                Using ``None`` as the *timeout_unit* argument is deprecated, use ``'step'`` instead.\n\n        expect_fail (bool, optional):\n            If ``True`` and the test fails a functional check via an ``assert`` statement, :class:`pytest.raises`,\n            :class:`pytest.warns`, or :class:`pytest.deprecated_call` the test is considered to have passed.\n            If ``True`` and the test passes successfully, the test is considered to have failed.\n\n        expect_error (exception type or tuple of exception types, optional):\n            Mark the result as a pass only if one of the exception types is raised in the test.\n            This is primarily for cocotb internal regression use for when a simulator error is expected.\n\n            Users are encouraged to use the following idiom instead::\n\n                @cocotb.test()\n                async def my_test(dut):\n                    try:\n                        await thing_that_should_fail()\n                    except ExceptionIExpect:\n                        pass\n                    else:\n                        assert False, \"Exception did not occur\"\n\n            .. versionchanged:: 1.3\n                Specific exception types can be expected\n\n            .. deprecated:: 1.5\n                Passing a :class:`bool` value is now deprecated.\n                Pass a specific :class:`Exception` or a tuple of Exceptions instead.\n\n        skip (bool, optional):\n            Don't execute this test as part of the regression. Test can still be run\n            manually by setting :make:var:`TESTCASE`.\n\n        stage (int)\n            Order tests logically into stages, where multiple tests can share a stage.\n            Defaults to 0.\n    \"\"\"\n\n    _id_count = 0  # used by the RegressionManager to sort tests in definition order\n\n    def __init__(\n        self,\n        f,\n        timeout_time=None,\n        timeout_unit=\"step\",\n        expect_fail=False,\n        expect_error=(),\n        skip=False,\n        stage=0,\n    ):\n        if timeout_unit is None:\n            warnings.warn(\n                'Using timeout_unit=None is deprecated, use timeout_unit=\"step\" instead.',\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            timeout_unit = \"step\"  # don't propagate deprecated value\n        self._id = self._id_count\n        type(self)._id_count += 1\n\n        if timeout_time is not None:\n            co = coroutine(f)\n\n            @functools.wraps(f)\n            async def f(*args, **kwargs):\n                running_co = co(*args, **kwargs)\n\n                try:\n                    res = await cocotb.triggers.with_timeout(\n                        running_co, self.timeout_time, self.timeout_unit\n                    )\n                except cocotb.result.SimTimeoutError:\n                    running_co.kill()\n                    raise\n                else:\n                    return res\n\n        super().__init__(f)\n\n        self.timeout_time = timeout_time\n        self.timeout_unit = timeout_unit\n        self.expect_fail = expect_fail\n        if isinstance(expect_error, bool):\n            warnings.warn(\n                \"Passing bool values to `except_error` option of `cocotb.test` is deprecated. \"\n                \"Pass a specific Exception type instead\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n        if expect_error is True:\n            expect_error = (BaseException,)\n        elif expect_error is False:\n            expect_error = ()\n        self.expect_error = expect_error\n        self.skip = skip\n        self.stage = stage\n        self.im_test = True  # For auto-regressions\n        self.name = self._func.__name__\n\n    def __call__(self, *args, **kwargs):\n        inst = self._func(*args, **kwargs)\n        coro = _RunningTest(inst, self)\n        return coro\n\n\nif sys.version_info < (3, 7):\n    Task = _Task\n    RunningTask = _Task\n    RunningCoroutine = _RunningCoroutine\n    RunningTest = _RunningTest\nelse:\n\n    def __getattr__(attr: str) -> typing.Any:\n        if attr in (\"Task\", \"RunningTask\"):\n            warnings.warn(\n                f\"The class {attr} has been renamed to cocotb.task.Task.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            attr = \"_Task\"\n        elif attr in (\"RunningCoroutine\", \"RunningTest\"):\n            warnings.warn(\n                f\"The class {attr} is now private. Update all uses to the parent class cocotb.task.Task.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            attr = f\"_{attr}\"\n        try:\n            return globals()[attr]\n        except KeyError:\n            raise AttributeError(\n                f\"module {__name__!r} has no attribute {attr!r}\"\n            ) from None\n", "path": "cocotb/decorators.py"}]}