We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
cunumeric does not issue unimplemented warnings for functions in submodules
For example, calling unsupported functions in the `random` module silently fall back to numpy instead of issuing a warning.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cunumeric/random/__init__.py`
Content:
```
1 # Copyright 2021-2022 NVIDIA Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 from __future__ import annotations
16 
17 import numpy.random as _nprandom
18 from cunumeric.coverage import clone_module
19 from cunumeric.runtime import runtime
20 
21 if runtime.has_curand:
22     from cunumeric.random.random import *
23     from cunumeric.random.bitgenerator import *
24     from cunumeric.random.generator import *
25 else:
26     from cunumeric.random.legacy import *
27 
28 clone_module(_nprandom, globals())
29 
30 del clone_module
31 del _nprandom
32
```

Path: `cunumeric/coverage.py`
Content:
```
1 # Copyright 2022 NVIDIA Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 from __future__ import annotations
16 
17 import warnings
18 from dataclasses import dataclass
19 from functools import wraps
20 from types import FunctionType, MethodDescriptorType, MethodType, ModuleType
21 from typing import Any, Container, Mapping, Optional, cast
22 
23 import numpy as np
24 from legate.core import track_provenance
25 from typing_extensions import Protocol
26 
27 from .runtime import runtime
28 from .utils import find_last_user_frames, find_last_user_stacklevel
29 
30 __all__ = ("clone_module", "clone_np_ndarray")
31 
32 FALLBACK_WARNING = (
33     "cuNumeric has not implemented {name} "
34     + "and is falling back to canonical numpy. "
35     + "You may notice significantly decreased performance "
36     + "for this function call."
37 )
38 
39 MOD_INTERNAL = {"__dir__", "__getattr__"}
40 
41 NDARRAY_INTERNAL = {
42     "__array_finalize__",
43     "__array_function__",
44     "__array_interface__",
45     "__array_prepare__",
46     "__array_priority__",
47     "__array_struct__",
48     "__array_ufunc__",
49     "__array_wrap__",
50 }
51 
52 
53 def filter_namespace(
54     ns: Mapping[str, Any],
55     *,
56     omit_names: Optional[Container[str]] = None,
57     omit_types: tuple[type, ...] = (),
58 ) -> dict[str, Any]:
59     omit_names = omit_names or set()
60     return {
61         attr: value
62         for attr, value in ns.items()
63         if attr not in omit_names and not isinstance(value, omit_types)
64     }
65 
66 
67 class AnyCallable(Protocol):
68     def __call__(self, *args: Any, **kwargs: Any) -> Any:
69         ...
70 
71 
72 @dataclass(frozen=True)
73 class CuWrapperMetadata:
74     implemented: bool
75     single: bool = False
76     multi: bool = False
77 
78 
79 class CuWrapped(AnyCallable, Protocol):
80     _cunumeric: CuWrapperMetadata
81     __wrapped__: AnyCallable
82     __name__: str
83     __qualname__: str
84 
85 
86 def implemented(
87     func: AnyCallable, prefix: str, name: str, reporting: bool = True
88 ) -> CuWrapped:
89     name = f"{prefix}.{name}"
90 
91     wrapper: CuWrapped
92 
93     if reporting:
94 
95         @wraps(func)
96         @track_provenance(runtime.legate_context)
97         def wrapper(*args: Any, **kwargs: Any) -> Any:
98             location = find_last_user_frames(
99                 not runtime.args.report_dump_callstack
100             )
101             runtime.record_api_call(
102                 name=name,
103                 location=location,
104                 implemented=True,
105             )
106             return func(*args, **kwargs)
107 
108     else:
109 
110         @wraps(func)
111         @track_provenance(runtime.legate_context)
112         def wrapper(*args: Any, **kwargs: Any) -> Any:
113             return func(*args, **kwargs)
114 
115     # This is incredibly ugly and unpleasant, but @wraps(func) doesn't handle
116     # ufuncs the way we need it to. The alternative would be to vendor and
117     # modify a custom version of @wraps
118     if hasattr(wrapper.__wrapped__, "_name"):
119         wrapper.__name__ = wrapper.__wrapped__._name
120         wrapper.__qualname__ = wrapper.__wrapped__._name
121 
122     # TODO (bev) Scraping text to set flags seems a bit fragile. It would be
123     # preferable to start with flags, and use those to update docstrings.
124     multi = "Multiple GPUs" in (getattr(func, "__doc__", None) or "")
125     single = "Single GPU" in (getattr(func, "__doc__", None) or "") or multi
126 
127     wrapper._cunumeric = CuWrapperMetadata(
128         implemented=True, single=single, multi=multi
129     )
130 
131     return wrapper
132 
133 
134 def unimplemented(
135     func: AnyCallable,
136     prefix: str,
137     name: str,
138     reporting: bool = True,
139     self_fallback: Optional[str] = None,
140 ) -> CuWrapped:
141     name = f"{prefix}.{name}"
142 
143     # Skip over NumPy's `__array_function__` dispatch wrapper, if present.
144     # NumPy adds `__array_function__` dispatch logic through decorators, but
145     # still makes the underlying code (which converts all array-like arguments
146     # to `numpy.ndarray` through `__array__`) available in the
147     # `_implementation` field.
148     # We have to skip the dispatch wrapper, otherwise we will trigger an
149     # infinite loop. Say we're dealing with a call to `cunumeric.foo`, and are
150     # trying to fall back to `numpy.foo`. If we didn't skip the dispatch
151     # wrapper of `numpy.foo`, then NumPy would ask
152     # `cunumeric.ndarray.__array_function__` to handle the call to `numpy.foo`,
153     # then `cunumeric.ndarray.__array_function__` would call `cunumeric.foo`,
154     # and we would end up here again.
155     func = getattr(func, "_implementation", func)
156 
157     wrapper: CuWrapped
158 
159     if reporting:
160 
161         @wraps(func)
162         def wrapper(*args: Any, **kwargs: Any) -> Any:
163             location = find_last_user_frames(
164                 not runtime.args.report_dump_callstack
165             )
166             runtime.record_api_call(
167                 name=name,
168                 location=location,
169                 implemented=False,
170             )
171             if self_fallback:
172                 self_value = getattr(args[0], self_fallback)()
173                 args = (self_value,) + args[1:]
174             return func(*args, **kwargs)
175 
176     else:
177 
178         @wraps(func)
179         def wrapper(*args: Any, **kwargs: Any) -> Any:
180             stacklevel = find_last_user_stacklevel()
181             warnings.warn(
182                 FALLBACK_WARNING.format(name=name),
183                 stacklevel=stacklevel,
184                 category=RuntimeWarning,
185             )
186             if self_fallback:
187                 self_value = getattr(args[0], self_fallback)()
188                 args = (self_value,) + args[1:]
189             return func(*args, **kwargs)
190 
191     wrapper._cunumeric = CuWrapperMetadata(implemented=False)
192 
193     return wrapper
194 
195 
196 def clone_module(
197     origin_module: ModuleType, new_globals: dict[str, Any]
198 ) -> None:
199     """Copy attributes from one module to another, excluding submodules
200 
201     Function types are wrapped with a decorator to report API calls. All
202     other values are copied as-is.
203 
204     Parameters
205     ----------
206     origin_module : ModuleTpe
207         Existing module to clone attributes from
208 
209     new_globals : dict
210         a globals() dict for the new module to clone into
211 
212     Returns
213     -------
214     None
215 
216     """
217     mod_name = origin_module.__name__
218 
219     missing = filter_namespace(
220         origin_module.__dict__,
221         omit_names=set(new_globals).union(MOD_INTERNAL),
222         omit_types=(ModuleType,),
223     )
224 
225     reporting = runtime.args.report_coverage
226 
227     from ._ufunc.ufunc import ufunc as lgufunc
228 
229     for attr, value in new_globals.items():
230         # Only need to wrap things that are in the origin module to begin with
231         if attr not in origin_module.__dict__:
232             continue
233         if isinstance(value, (FunctionType, lgufunc)):
234             wrapped = implemented(
235                 cast(AnyCallable, value), mod_name, attr, reporting=reporting
236             )
237             new_globals[attr] = wrapped
238 
239     from numpy import ufunc as npufunc
240 
241     for attr, value in missing.items():
242         if isinstance(value, (FunctionType, npufunc)):
243             wrapped = unimplemented(value, mod_name, attr, reporting=reporting)
244             new_globals[attr] = wrapped
245         else:
246             new_globals[attr] = value
247 
248 
249 def should_wrap(obj: object) -> bool:
250     return isinstance(obj, (FunctionType, MethodType, MethodDescriptorType))
251 
252 
253 def clone_np_ndarray(cls: type) -> type:
254     """Copy attributes from np.ndarray to cunumeric.ndarray
255 
256     Method types are wrapped with a decorator to report API calls. All
257     other values are copied as-is.
258 
259     """
260 
261     origin_class = np.ndarray
262 
263     class_name = f"{origin_class.__module__}.{origin_class.__name__}"
264 
265     missing = filter_namespace(
266         origin_class.__dict__,
267         # this simply omits ndarray internal methods for any class. If
268         # we ever need to wrap more classes we may need to generalize to
269         # per-class specification of internal names to skip
270         omit_names=set(cls.__dict__).union(NDARRAY_INTERNAL),
271     )
272 
273     reporting = runtime.args.report_coverage
274 
275     for attr, value in cls.__dict__.items():
276         # Only need to wrap things that are in the origin class to begin with
277         if not hasattr(origin_class, attr):
278             continue
279         if should_wrap(value):
280             wrapped = implemented(value, class_name, attr, reporting=reporting)
281             setattr(cls, attr, wrapped)
282 
283     for attr, value in missing.items():
284         if should_wrap(value):
285             wrapped = unimplemented(
286                 value,
287                 class_name,
288                 attr,
289                 reporting=reporting,
290                 self_fallback="__array__",
291             )
292             setattr(cls, attr, wrapped)
293         else:
294             setattr(cls, attr, value)
295 
296     return cls
297 
298 
299 def is_implemented(obj: Any) -> bool:
300     return hasattr(obj, "_cunumeric") and obj._cunumeric.implemented
301 
302 
303 def is_single(obj: Any) -> bool:
304     return hasattr(obj, "_cunumeric") and obj._cunumeric.single
305 
306 
307 def is_multi(obj: Any) -> bool:
308     return hasattr(obj, "_cunumeric") and obj._cunumeric.multi
309
```
--- 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/cunumeric/coverage.py b/cunumeric/coverage.py
--- a/cunumeric/coverage.py
+++ b/cunumeric/coverage.py
@@ -17,7 +17,13 @@
 import warnings
 from dataclasses import dataclass
 from functools import wraps
-from types import FunctionType, MethodDescriptorType, MethodType, ModuleType
+from types import (
+    BuiltinFunctionType,
+    FunctionType,
+    MethodDescriptorType,
+    MethodType,
+    ModuleType,
+)
 from typing import Any, Container, Mapping, Optional, cast
 
 import numpy as np
@@ -194,7 +200,9 @@
 
 
 def clone_module(
-    origin_module: ModuleType, new_globals: dict[str, Any]
+    origin_module: ModuleType,
+    new_globals: dict[str, Any],
+    include_builtin_function_type: bool = False,
 ) -> None:
     """Copy attributes from one module to another, excluding submodules
 
@@ -230,7 +238,10 @@
         # Only need to wrap things that are in the origin module to begin with
         if attr not in origin_module.__dict__:
             continue
-        if isinstance(value, (FunctionType, lgufunc)):
+        if isinstance(value, (FunctionType, lgufunc)) or (
+            include_builtin_function_type
+            and isinstance(value, BuiltinFunctionType)
+        ):
             wrapped = implemented(
                 cast(AnyCallable, value), mod_name, attr, reporting=reporting
             )
@@ -239,7 +250,10 @@
     from numpy import ufunc as npufunc
 
     for attr, value in missing.items():
-        if isinstance(value, (FunctionType, npufunc)):
+        if isinstance(value, (FunctionType, npufunc)) or (
+            include_builtin_function_type
+            and isinstance(value, BuiltinFunctionType)
+        ):
             wrapped = unimplemented(value, mod_name, attr, reporting=reporting)
             new_globals[attr] = wrapped
         else:
diff --git a/cunumeric/random/__init__.py b/cunumeric/random/__init__.py
--- a/cunumeric/random/__init__.py
+++ b/cunumeric/random/__init__.py
@@ -25,7 +25,7 @@
 else:
     from cunumeric.random.legacy import *
 
-clone_module(_nprandom, globals())
+clone_module(_nprandom, globals(), include_builtin_function_type=True)
 
 del clone_module
 del _nprandom

{"golden_diff": "diff --git a/cunumeric/coverage.py b/cunumeric/coverage.py\n--- a/cunumeric/coverage.py\n+++ b/cunumeric/coverage.py\n@@ -17,7 +17,13 @@\n import warnings\n from dataclasses import dataclass\n from functools import wraps\n-from types import FunctionType, MethodDescriptorType, MethodType, ModuleType\n+from types import (\n+    BuiltinFunctionType,\n+    FunctionType,\n+    MethodDescriptorType,\n+    MethodType,\n+    ModuleType,\n+)\n from typing import Any, Container, Mapping, Optional, cast\n \n import numpy as np\n@@ -194,7 +200,9 @@\n \n \n def clone_module(\n-    origin_module: ModuleType, new_globals: dict[str, Any]\n+    origin_module: ModuleType,\n+    new_globals: dict[str, Any],\n+    include_builtin_function_type: bool = False,\n ) -> None:\n     \"\"\"Copy attributes from one module to another, excluding submodules\n \n@@ -230,7 +238,10 @@\n         # Only need to wrap things that are in the origin module to begin with\n         if attr not in origin_module.__dict__:\n             continue\n-        if isinstance(value, (FunctionType, lgufunc)):\n+        if isinstance(value, (FunctionType, lgufunc)) or (\n+            include_builtin_function_type\n+            and isinstance(value, BuiltinFunctionType)\n+        ):\n             wrapped = implemented(\n                 cast(AnyCallable, value), mod_name, attr, reporting=reporting\n             )\n@@ -239,7 +250,10 @@\n     from numpy import ufunc as npufunc\n \n     for attr, value in missing.items():\n-        if isinstance(value, (FunctionType, npufunc)):\n+        if isinstance(value, (FunctionType, npufunc)) or (\n+            include_builtin_function_type\n+            and isinstance(value, BuiltinFunctionType)\n+        ):\n             wrapped = unimplemented(value, mod_name, attr, reporting=reporting)\n             new_globals[attr] = wrapped\n         else:\ndiff --git a/cunumeric/random/__init__.py b/cunumeric/random/__init__.py\n--- a/cunumeric/random/__init__.py\n+++ b/cunumeric/random/__init__.py\n@@ -25,7 +25,7 @@\n else:\n     from cunumeric.random.legacy import *\n \n-clone_module(_nprandom, globals())\n+clone_module(_nprandom, globals(), include_builtin_function_type=True)\n \n del clone_module\n del _nprandom\n", "issue": "cunumeric does not issue unimplemented warnings for functions in submodules\nFor example, calling unsupported functions in the `random` module silently fall back to numpy instead of issuing a warning.\n", "before_files": [{"content": "# Copyright 2021-2022 NVIDIA Corporation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nfrom __future__ import annotations\n\nimport numpy.random as _nprandom\nfrom cunumeric.coverage import clone_module\nfrom cunumeric.runtime import runtime\n\nif runtime.has_curand:\n    from cunumeric.random.random import *\n    from cunumeric.random.bitgenerator import *\n    from cunumeric.random.generator import *\nelse:\n    from cunumeric.random.legacy import *\n\nclone_module(_nprandom, globals())\n\ndel clone_module\ndel _nprandom\n", "path": "cunumeric/random/__init__.py"}, {"content": "# Copyright 2022 NVIDIA Corporation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nfrom __future__ import annotations\n\nimport warnings\nfrom dataclasses import dataclass\nfrom functools import wraps\nfrom types import FunctionType, MethodDescriptorType, MethodType, ModuleType\nfrom typing import Any, Container, Mapping, Optional, cast\n\nimport numpy as np\nfrom legate.core import track_provenance\nfrom typing_extensions import Protocol\n\nfrom .runtime import runtime\nfrom .utils import find_last_user_frames, find_last_user_stacklevel\n\n__all__ = (\"clone_module\", \"clone_np_ndarray\")\n\nFALLBACK_WARNING = (\n    \"cuNumeric has not implemented {name} \"\n    + \"and is falling back to canonical numpy. \"\n    + \"You may notice significantly decreased performance \"\n    + \"for this function call.\"\n)\n\nMOD_INTERNAL = {\"__dir__\", \"__getattr__\"}\n\nNDARRAY_INTERNAL = {\n    \"__array_finalize__\",\n    \"__array_function__\",\n    \"__array_interface__\",\n    \"__array_prepare__\",\n    \"__array_priority__\",\n    \"__array_struct__\",\n    \"__array_ufunc__\",\n    \"__array_wrap__\",\n}\n\n\ndef filter_namespace(\n    ns: Mapping[str, Any],\n    *,\n    omit_names: Optional[Container[str]] = None,\n    omit_types: tuple[type, ...] = (),\n) -> dict[str, Any]:\n    omit_names = omit_names or set()\n    return {\n        attr: value\n        for attr, value in ns.items()\n        if attr not in omit_names and not isinstance(value, omit_types)\n    }\n\n\nclass AnyCallable(Protocol):\n    def __call__(self, *args: Any, **kwargs: Any) -> Any:\n        ...\n\n\n@dataclass(frozen=True)\nclass CuWrapperMetadata:\n    implemented: bool\n    single: bool = False\n    multi: bool = False\n\n\nclass CuWrapped(AnyCallable, Protocol):\n    _cunumeric: CuWrapperMetadata\n    __wrapped__: AnyCallable\n    __name__: str\n    __qualname__: str\n\n\ndef implemented(\n    func: AnyCallable, prefix: str, name: str, reporting: bool = True\n) -> CuWrapped:\n    name = f\"{prefix}.{name}\"\n\n    wrapper: CuWrapped\n\n    if reporting:\n\n        @wraps(func)\n        @track_provenance(runtime.legate_context)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            location = find_last_user_frames(\n                not runtime.args.report_dump_callstack\n            )\n            runtime.record_api_call(\n                name=name,\n                location=location,\n                implemented=True,\n            )\n            return func(*args, **kwargs)\n\n    else:\n\n        @wraps(func)\n        @track_provenance(runtime.legate_context)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            return func(*args, **kwargs)\n\n    # This is incredibly ugly and unpleasant, but @wraps(func) doesn't handle\n    # ufuncs the way we need it to. The alternative would be to vendor and\n    # modify a custom version of @wraps\n    if hasattr(wrapper.__wrapped__, \"_name\"):\n        wrapper.__name__ = wrapper.__wrapped__._name\n        wrapper.__qualname__ = wrapper.__wrapped__._name\n\n    # TODO (bev) Scraping text to set flags seems a bit fragile. It would be\n    # preferable to start with flags, and use those to update docstrings.\n    multi = \"Multiple GPUs\" in (getattr(func, \"__doc__\", None) or \"\")\n    single = \"Single GPU\" in (getattr(func, \"__doc__\", None) or \"\") or multi\n\n    wrapper._cunumeric = CuWrapperMetadata(\n        implemented=True, single=single, multi=multi\n    )\n\n    return wrapper\n\n\ndef unimplemented(\n    func: AnyCallable,\n    prefix: str,\n    name: str,\n    reporting: bool = True,\n    self_fallback: Optional[str] = None,\n) -> CuWrapped:\n    name = f\"{prefix}.{name}\"\n\n    # Skip over NumPy's `__array_function__` dispatch wrapper, if present.\n    # NumPy adds `__array_function__` dispatch logic through decorators, but\n    # still makes the underlying code (which converts all array-like arguments\n    # to `numpy.ndarray` through `__array__`) available in the\n    # `_implementation` field.\n    # We have to skip the dispatch wrapper, otherwise we will trigger an\n    # infinite loop. Say we're dealing with a call to `cunumeric.foo`, and are\n    # trying to fall back to `numpy.foo`. If we didn't skip the dispatch\n    # wrapper of `numpy.foo`, then NumPy would ask\n    # `cunumeric.ndarray.__array_function__` to handle the call to `numpy.foo`,\n    # then `cunumeric.ndarray.__array_function__` would call `cunumeric.foo`,\n    # and we would end up here again.\n    func = getattr(func, \"_implementation\", func)\n\n    wrapper: CuWrapped\n\n    if reporting:\n\n        @wraps(func)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            location = find_last_user_frames(\n                not runtime.args.report_dump_callstack\n            )\n            runtime.record_api_call(\n                name=name,\n                location=location,\n                implemented=False,\n            )\n            if self_fallback:\n                self_value = getattr(args[0], self_fallback)()\n                args = (self_value,) + args[1:]\n            return func(*args, **kwargs)\n\n    else:\n\n        @wraps(func)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            stacklevel = find_last_user_stacklevel()\n            warnings.warn(\n                FALLBACK_WARNING.format(name=name),\n                stacklevel=stacklevel,\n                category=RuntimeWarning,\n            )\n            if self_fallback:\n                self_value = getattr(args[0], self_fallback)()\n                args = (self_value,) + args[1:]\n            return func(*args, **kwargs)\n\n    wrapper._cunumeric = CuWrapperMetadata(implemented=False)\n\n    return wrapper\n\n\ndef clone_module(\n    origin_module: ModuleType, new_globals: dict[str, Any]\n) -> None:\n    \"\"\"Copy attributes from one module to another, excluding submodules\n\n    Function types are wrapped with a decorator to report API calls. All\n    other values are copied as-is.\n\n    Parameters\n    ----------\n    origin_module : ModuleTpe\n        Existing module to clone attributes from\n\n    new_globals : dict\n        a globals() dict for the new module to clone into\n\n    Returns\n    -------\n    None\n\n    \"\"\"\n    mod_name = origin_module.__name__\n\n    missing = filter_namespace(\n        origin_module.__dict__,\n        omit_names=set(new_globals).union(MOD_INTERNAL),\n        omit_types=(ModuleType,),\n    )\n\n    reporting = runtime.args.report_coverage\n\n    from ._ufunc.ufunc import ufunc as lgufunc\n\n    for attr, value in new_globals.items():\n        # Only need to wrap things that are in the origin module to begin with\n        if attr not in origin_module.__dict__:\n            continue\n        if isinstance(value, (FunctionType, lgufunc)):\n            wrapped = implemented(\n                cast(AnyCallable, value), mod_name, attr, reporting=reporting\n            )\n            new_globals[attr] = wrapped\n\n    from numpy import ufunc as npufunc\n\n    for attr, value in missing.items():\n        if isinstance(value, (FunctionType, npufunc)):\n            wrapped = unimplemented(value, mod_name, attr, reporting=reporting)\n            new_globals[attr] = wrapped\n        else:\n            new_globals[attr] = value\n\n\ndef should_wrap(obj: object) -> bool:\n    return isinstance(obj, (FunctionType, MethodType, MethodDescriptorType))\n\n\ndef clone_np_ndarray(cls: type) -> type:\n    \"\"\"Copy attributes from np.ndarray to cunumeric.ndarray\n\n    Method types are wrapped with a decorator to report API calls. All\n    other values are copied as-is.\n\n    \"\"\"\n\n    origin_class = np.ndarray\n\n    class_name = f\"{origin_class.__module__}.{origin_class.__name__}\"\n\n    missing = filter_namespace(\n        origin_class.__dict__,\n        # this simply omits ndarray internal methods for any class. If\n        # we ever need to wrap more classes we may need to generalize to\n        # per-class specification of internal names to skip\n        omit_names=set(cls.__dict__).union(NDARRAY_INTERNAL),\n    )\n\n    reporting = runtime.args.report_coverage\n\n    for attr, value in cls.__dict__.items():\n        # Only need to wrap things that are in the origin class to begin with\n        if not hasattr(origin_class, attr):\n            continue\n        if should_wrap(value):\n            wrapped = implemented(value, class_name, attr, reporting=reporting)\n            setattr(cls, attr, wrapped)\n\n    for attr, value in missing.items():\n        if should_wrap(value):\n            wrapped = unimplemented(\n                value,\n                class_name,\n                attr,\n                reporting=reporting,\n                self_fallback=\"__array__\",\n            )\n            setattr(cls, attr, wrapped)\n        else:\n            setattr(cls, attr, value)\n\n    return cls\n\n\ndef is_implemented(obj: Any) -> bool:\n    return hasattr(obj, \"_cunumeric\") and obj._cunumeric.implemented\n\n\ndef is_single(obj: Any) -> bool:\n    return hasattr(obj, \"_cunumeric\") and obj._cunumeric.single\n\n\ndef is_multi(obj: Any) -> bool:\n    return hasattr(obj, \"_cunumeric\") and obj._cunumeric.multi\n", "path": "cunumeric/coverage.py"}], "after_files": [{"content": "# Copyright 2021-2022 NVIDIA Corporation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nfrom __future__ import annotations\n\nimport numpy.random as _nprandom\nfrom cunumeric.coverage import clone_module\nfrom cunumeric.runtime import runtime\n\nif runtime.has_curand:\n    from cunumeric.random.random import *\n    from cunumeric.random.bitgenerator import *\n    from cunumeric.random.generator import *\nelse:\n    from cunumeric.random.legacy import *\n\nclone_module(_nprandom, globals(), include_builtin_function_type=True)\n\ndel clone_module\ndel _nprandom\n", "path": "cunumeric/random/__init__.py"}, {"content": "# Copyright 2022 NVIDIA Corporation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nfrom __future__ import annotations\n\nimport warnings\nfrom dataclasses import dataclass\nfrom functools import wraps\nfrom types import (\n    BuiltinFunctionType,\n    FunctionType,\n    MethodDescriptorType,\n    MethodType,\n    ModuleType,\n)\nfrom typing import Any, Container, Mapping, Optional, cast\n\nimport numpy as np\nfrom legate.core import track_provenance\nfrom typing_extensions import Protocol\n\nfrom .runtime import runtime\nfrom .utils import find_last_user_frames, find_last_user_stacklevel\n\n__all__ = (\"clone_module\", \"clone_np_ndarray\")\n\nFALLBACK_WARNING = (\n    \"cuNumeric has not implemented {name} \"\n    + \"and is falling back to canonical numpy. \"\n    + \"You may notice significantly decreased performance \"\n    + \"for this function call.\"\n)\n\nMOD_INTERNAL = {\"__dir__\", \"__getattr__\"}\n\nNDARRAY_INTERNAL = {\n    \"__array_finalize__\",\n    \"__array_function__\",\n    \"__array_interface__\",\n    \"__array_prepare__\",\n    \"__array_priority__\",\n    \"__array_struct__\",\n    \"__array_ufunc__\",\n    \"__array_wrap__\",\n}\n\n\ndef filter_namespace(\n    ns: Mapping[str, Any],\n    *,\n    omit_names: Optional[Container[str]] = None,\n    omit_types: tuple[type, ...] = (),\n) -> dict[str, Any]:\n    omit_names = omit_names or set()\n    return {\n        attr: value\n        for attr, value in ns.items()\n        if attr not in omit_names and not isinstance(value, omit_types)\n    }\n\n\nclass AnyCallable(Protocol):\n    def __call__(self, *args: Any, **kwargs: Any) -> Any:\n        ...\n\n\n@dataclass(frozen=True)\nclass CuWrapperMetadata:\n    implemented: bool\n    single: bool = False\n    multi: bool = False\n\n\nclass CuWrapped(AnyCallable, Protocol):\n    _cunumeric: CuWrapperMetadata\n    __wrapped__: AnyCallable\n    __name__: str\n    __qualname__: str\n\n\ndef implemented(\n    func: AnyCallable, prefix: str, name: str, reporting: bool = True\n) -> CuWrapped:\n    name = f\"{prefix}.{name}\"\n\n    wrapper: CuWrapped\n\n    if reporting:\n\n        @wraps(func)\n        @track_provenance(runtime.legate_context)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            location = find_last_user_frames(\n                not runtime.args.report_dump_callstack\n            )\n            runtime.record_api_call(\n                name=name,\n                location=location,\n                implemented=True,\n            )\n            return func(*args, **kwargs)\n\n    else:\n\n        @wraps(func)\n        @track_provenance(runtime.legate_context)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            return func(*args, **kwargs)\n\n    # This is incredibly ugly and unpleasant, but @wraps(func) doesn't handle\n    # ufuncs the way we need it to. The alternative would be to vendor and\n    # modify a custom version of @wraps\n    if hasattr(wrapper.__wrapped__, \"_name\"):\n        wrapper.__name__ = wrapper.__wrapped__._name\n        wrapper.__qualname__ = wrapper.__wrapped__._name\n\n    # TODO (bev) Scraping text to set flags seems a bit fragile. It would be\n    # preferable to start with flags, and use those to update docstrings.\n    multi = \"Multiple GPUs\" in (getattr(func, \"__doc__\", None) or \"\")\n    single = \"Single GPU\" in (getattr(func, \"__doc__\", None) or \"\") or multi\n\n    wrapper._cunumeric = CuWrapperMetadata(\n        implemented=True, single=single, multi=multi\n    )\n\n    return wrapper\n\n\ndef unimplemented(\n    func: AnyCallable,\n    prefix: str,\n    name: str,\n    reporting: bool = True,\n    self_fallback: Optional[str] = None,\n) -> CuWrapped:\n    name = f\"{prefix}.{name}\"\n\n    # Skip over NumPy's `__array_function__` dispatch wrapper, if present.\n    # NumPy adds `__array_function__` dispatch logic through decorators, but\n    # still makes the underlying code (which converts all array-like arguments\n    # to `numpy.ndarray` through `__array__`) available in the\n    # `_implementation` field.\n    # We have to skip the dispatch wrapper, otherwise we will trigger an\n    # infinite loop. Say we're dealing with a call to `cunumeric.foo`, and are\n    # trying to fall back to `numpy.foo`. If we didn't skip the dispatch\n    # wrapper of `numpy.foo`, then NumPy would ask\n    # `cunumeric.ndarray.__array_function__` to handle the call to `numpy.foo`,\n    # then `cunumeric.ndarray.__array_function__` would call `cunumeric.foo`,\n    # and we would end up here again.\n    func = getattr(func, \"_implementation\", func)\n\n    wrapper: CuWrapped\n\n    if reporting:\n\n        @wraps(func)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            location = find_last_user_frames(\n                not runtime.args.report_dump_callstack\n            )\n            runtime.record_api_call(\n                name=name,\n                location=location,\n                implemented=False,\n            )\n            if self_fallback:\n                self_value = getattr(args[0], self_fallback)()\n                args = (self_value,) + args[1:]\n            return func(*args, **kwargs)\n\n    else:\n\n        @wraps(func)\n        def wrapper(*args: Any, **kwargs: Any) -> Any:\n            stacklevel = find_last_user_stacklevel()\n            warnings.warn(\n                FALLBACK_WARNING.format(name=name),\n                stacklevel=stacklevel,\n                category=RuntimeWarning,\n            )\n            if self_fallback:\n                self_value = getattr(args[0], self_fallback)()\n                args = (self_value,) + args[1:]\n            return func(*args, **kwargs)\n\n    wrapper._cunumeric = CuWrapperMetadata(implemented=False)\n\n    return wrapper\n\n\ndef clone_module(\n    origin_module: ModuleType,\n    new_globals: dict[str, Any],\n    include_builtin_function_type: bool = False,\n) -> None:\n    \"\"\"Copy attributes from one module to another, excluding submodules\n\n    Function types are wrapped with a decorator to report API calls. All\n    other values are copied as-is.\n\n    Parameters\n    ----------\n    origin_module : ModuleTpe\n        Existing module to clone attributes from\n\n    new_globals : dict\n        a globals() dict for the new module to clone into\n\n    Returns\n    -------\n    None\n\n    \"\"\"\n    mod_name = origin_module.__name__\n\n    missing = filter_namespace(\n        origin_module.__dict__,\n        omit_names=set(new_globals).union(MOD_INTERNAL),\n        omit_types=(ModuleType,),\n    )\n\n    reporting = runtime.args.report_coverage\n\n    from ._ufunc.ufunc import ufunc as lgufunc\n\n    for attr, value in new_globals.items():\n        # Only need to wrap things that are in the origin module to begin with\n        if attr not in origin_module.__dict__:\n            continue\n        if isinstance(value, (FunctionType, lgufunc)) or (\n            include_builtin_function_type\n            and isinstance(value, BuiltinFunctionType)\n        ):\n            wrapped = implemented(\n                cast(AnyCallable, value), mod_name, attr, reporting=reporting\n            )\n            new_globals[attr] = wrapped\n\n    from numpy import ufunc as npufunc\n\n    for attr, value in missing.items():\n        if isinstance(value, (FunctionType, npufunc)) or (\n            include_builtin_function_type\n            and isinstance(value, BuiltinFunctionType)\n        ):\n            wrapped = unimplemented(value, mod_name, attr, reporting=reporting)\n            new_globals[attr] = wrapped\n        else:\n            new_globals[attr] = value\n\n\ndef should_wrap(obj: object) -> bool:\n    return isinstance(obj, (FunctionType, MethodType, MethodDescriptorType))\n\n\ndef clone_np_ndarray(cls: type) -> type:\n    \"\"\"Copy attributes from np.ndarray to cunumeric.ndarray\n\n    Method types are wrapped with a decorator to report API calls. All\n    other values are copied as-is.\n\n    \"\"\"\n\n    origin_class = np.ndarray\n\n    class_name = f\"{origin_class.__module__}.{origin_class.__name__}\"\n\n    missing = filter_namespace(\n        origin_class.__dict__,\n        # this simply omits ndarray internal methods for any class. If\n        # we ever need to wrap more classes we may need to generalize to\n        # per-class specification of internal names to skip\n        omit_names=set(cls.__dict__).union(NDARRAY_INTERNAL),\n    )\n\n    reporting = runtime.args.report_coverage\n\n    for attr, value in cls.__dict__.items():\n        # Only need to wrap things that are in the origin class to begin with\n        if not hasattr(origin_class, attr):\n            continue\n        if should_wrap(value):\n            wrapped = implemented(value, class_name, attr, reporting=reporting)\n            setattr(cls, attr, wrapped)\n\n    for attr, value in missing.items():\n        if should_wrap(value):\n            wrapped = unimplemented(\n                value,\n                class_name,\n                attr,\n                reporting=reporting,\n                self_fallback=\"__array__\",\n            )\n            setattr(cls, attr, wrapped)\n        else:\n            setattr(cls, attr, value)\n\n    return cls\n\n\ndef is_implemented(obj: Any) -> bool:\n    return hasattr(obj, \"_cunumeric\") and obj._cunumeric.implemented\n\n\ndef is_single(obj: Any) -> bool:\n    return hasattr(obj, \"_cunumeric\") and obj._cunumeric.single\n\n\ndef is_multi(obj: Any) -> bool:\n    return hasattr(obj, \"_cunumeric\") and obj._cunumeric.multi\n", "path": "cunumeric/coverage.py"}]}