We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Always print warning message about min_package
**Describe the bug**
/opt/monai/monai/utils/module.py:100: UserWarning: <module 'pkg_resources' from '/opt/conda/lib/python3.8/site-packages/pkg_resources/__init__.py'> has no attribute __version__ in min_version check.
  warnings.warn(f"{the_module} has no attribute __version__ in min_version check.")


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `monai/utils/module.py`
Content:
```
1 # Copyright 2020 - 2021 MONAI Consortium
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #     http://www.apache.org/licenses/LICENSE-2.0
6 # Unless required by applicable law or agreed to in writing, software
7 # distributed under the License is distributed on an "AS IS" BASIS,
8 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 # See the License for the specific language governing permissions and
10 # limitations under the License.
11 
12 import inspect
13 import sys
14 import warnings
15 from importlib import import_module
16 from pkgutil import walk_packages
17 from re import match
18 from typing import Any, Callable, List, Sequence, Tuple, Union
19 
20 import torch
21 
22 from .misc import ensure_tuple
23 
24 OPTIONAL_IMPORT_MSG_FMT = "{}"
25 
26 __all__ = [
27     "InvalidPyTorchVersionError",
28     "OptionalImportError",
29     "exact_version",
30     "export",
31     "min_version",
32     "optional_import",
33     "load_submodules",
34     "get_full_type_name",
35     "has_option",
36     "get_package_version",
37     "get_torch_version_tuple",
38     "PT_BEFORE_1_7",
39 ]
40 
41 
42 def export(modname):
43     """
44     Make the decorated object a member of the named module. This will also add the object under its aliases if it has
45     a `__aliases__` member, thus this decorator should be before the `alias` decorator to pick up those names. Alias
46     names which conflict with package names or existing members will be ignored.
47     """
48 
49     def _inner(obj):
50         mod = import_module(modname)
51         if not hasattr(mod, obj.__name__):
52             setattr(mod, obj.__name__, obj)
53 
54             # add the aliases for `obj` to the target module
55             for alias in getattr(obj, "__aliases__", ()):
56                 if not hasattr(mod, alias):
57                     setattr(mod, alias, obj)
58 
59         return obj
60 
61     return _inner
62 
63 
64 def load_submodules(basemod, load_all: bool = True, exclude_pattern: str = "(.*[tT]est.*)|(_.*)"):
65     """
66     Traverse the source of the module structure starting with module `basemod`, loading all packages plus all files if
67     `load_all` is True, excluding anything whose name matches `exclude_pattern`.
68     """
69     submodules = []
70     err_mod: List[str] = []
71     for importer, name, is_pkg in walk_packages(
72         basemod.__path__, prefix=basemod.__name__ + ".", onerror=err_mod.append
73     ):
74         if (is_pkg or load_all) and name not in sys.modules and match(exclude_pattern, name) is None:
75             try:
76                 mod = import_module(name)
77                 importer.find_module(name).load_module(name)  # type: ignore
78                 submodules.append(mod)
79             except OptionalImportError:
80                 pass  # could not import the optional deps., they are ignored
81 
82     return submodules, err_mod
83 
84 
85 def get_full_type_name(typeobj):
86     module = typeobj.__module__
87     if module is None or module == str.__class__.__module__:
88         return typeobj.__name__  # Avoid reporting __builtin__
89     return module + "." + typeobj.__name__
90 
91 
92 def min_version(the_module, min_version_str: str = "") -> bool:
93     """
94     Convert version strings into tuples of int and compare them.
95 
96     Returns True if the module's version is greater or equal to the 'min_version'.
97     When min_version_str is not provided, it always returns True.
98     """
99     if not min_version_str:
100         return True  # always valid version
101     if not hasattr(the_module, "__version__"):
102         warnings.warn(f"{the_module} has no attribute __version__ in min_version check.")
103         return True  # min_version is the default, shouldn't be noisy
104     mod_version = tuple(int(x) for x in the_module.__version__.split(".")[:2])
105     required = tuple(int(x) for x in min_version_str.split(".")[:2])
106     return mod_version >= required
107 
108 
109 def exact_version(the_module, version_str: str = "") -> bool:
110     """
111     Returns True if the module's __version__ matches version_str
112     """
113     if not hasattr(the_module, "__version__"):
114         warnings.warn(f"{the_module} has no attribute __version__ in exact_version check.")
115         return False
116     return bool(the_module.__version__ == version_str)
117 
118 
119 class InvalidPyTorchVersionError(Exception):
120     """
121     Raised when called function or method requires a more recent
122     PyTorch version than that installed.
123     """
124 
125     def __init__(self, required_version, name):
126         message = f"{name} requires PyTorch version {required_version} or later"
127         super().__init__(message)
128 
129 
130 class OptionalImportError(ImportError):
131     """
132     Could not import APIs from an optional dependency.
133     """
134 
135 
136 def optional_import(
137     module: str,
138     version: str = "",
139     version_checker: Callable[..., bool] = min_version,
140     name: str = "",
141     descriptor: str = OPTIONAL_IMPORT_MSG_FMT,
142     version_args=None,
143     allow_namespace_pkg: bool = False,
144 ) -> Tuple[Any, bool]:
145     """
146     Imports an optional module specified by `module` string.
147     Any importing related exceptions will be stored, and exceptions raise lazily
148     when attempting to use the failed-to-import module.
149 
150     Args:
151         module: name of the module to be imported.
152         version: version string used by the version_checker.
153         version_checker: a callable to check the module version, Defaults to monai.utils.min_version.
154         name: a non-module attribute (such as method/class) to import from the imported module.
155         descriptor: a format string for the final error message when using a not imported module.
156         version_args: additional parameters to the version checker.
157         allow_namespace_pkg: whether importing a namespace package is allowed. Defaults to False.
158 
159     Returns:
160         The imported module and a boolean flag indicating whether the import is successful.
161 
162     Examples::
163 
164         >>> torch, flag = optional_import('torch', '1.1')
165         >>> print(torch, flag)
166         <module 'torch' from 'python/lib/python3.6/site-packages/torch/__init__.py'> True
167 
168         >>> the_module, flag = optional_import('unknown_module')
169         >>> print(flag)
170         False
171         >>> the_module.method  # trying to access a module which is not imported
172         OptionalImportError: import unknown_module (No module named 'unknown_module').
173 
174         >>> torch, flag = optional_import('torch', '42', exact_version)
175         >>> torch.nn  # trying to access a module for which there isn't a proper version imported
176         OptionalImportError: import torch (requires version '42' by 'exact_version').
177 
178         >>> conv, flag = optional_import('torch.nn.functional', '1.0', name='conv1d')
179         >>> print(conv)
180         <built-in method conv1d of type object at 0x11a49eac0>
181 
182         >>> conv, flag = optional_import('torch.nn.functional', '42', name='conv1d')
183         >>> conv()  # trying to use a function from the not successfully imported module (due to unmatched version)
184         OptionalImportError: from torch.nn.functional import conv1d (requires version '42' by 'min_version').
185     """
186 
187     tb = None
188     exception_str = ""
189     if name:
190         actual_cmd = f"from {module} import {name}"
191     else:
192         actual_cmd = f"import {module}"
193     try:
194         pkg = __import__(module)  # top level module
195         the_module = import_module(module)
196         if not allow_namespace_pkg:
197             is_namespace = getattr(the_module, "__file__", None) is None and hasattr(the_module, "__path__")
198             if is_namespace:
199                 raise AssertionError
200         if name:  # user specified to load class/function/... from the module
201             the_module = getattr(the_module, name)
202     except Exception as import_exception:  # any exceptions during import
203         tb = import_exception.__traceback__
204         exception_str = f"{import_exception}"
205     else:  # found the module
206         if version_args and version_checker(pkg, f"{version}", version_args):
207             return the_module, True
208         if not version_args and version_checker(pkg, f"{version}"):
209             return the_module, True
210 
211     # preparing lazy error message
212     msg = descriptor.format(actual_cmd)
213     if version and tb is None:  # a pure version issue
214         msg += f" (requires '{module} {version}' by '{version_checker.__name__}')"
215     if exception_str:
216         msg += f" ({exception_str})"
217 
218     class _LazyRaise:
219         def __init__(self, *_args, **_kwargs):
220             _default_msg = (
221                 f"{msg}."
222                 + "\n\nFor details about installing the optional dependencies, please visit:"
223                 + "\n    https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies"
224             )
225             if tb is None:
226                 self._exception = OptionalImportError(_default_msg)
227             else:
228                 self._exception = OptionalImportError(_default_msg).with_traceback(tb)
229 
230         def __getattr__(self, name):
231             """
232             Raises:
233                 OptionalImportError: When you call this method.
234             """
235             raise self._exception
236 
237         def __call__(self, *_args, **_kwargs):
238             """
239             Raises:
240                 OptionalImportError: When you call this method.
241             """
242             raise self._exception
243 
244     return _LazyRaise(), False
245 
246 
247 def has_option(obj, keywords: Union[str, Sequence[str]]) -> bool:
248     """
249     Return a boolean indicating whether the given callable `obj` has the `keywords` in its signature.
250     """
251     if not callable(obj):
252         return False
253     sig = inspect.signature(obj)
254     return all(key in sig.parameters for key in ensure_tuple(keywords))
255 
256 
257 def get_package_version(dep_name, default="NOT INSTALLED or UNKNOWN VERSION."):
258     """
259     Try to load package and get version. If not found, return `default`.
260     """
261     dep, has_dep = optional_import(dep_name)
262     if has_dep and hasattr(dep, "__version__"):
263         return dep.__version__
264     return default
265 
266 
267 def get_torch_version_tuple():
268     """
269     Returns:
270         tuple of ints represents the pytorch major/minor version.
271     """
272     return tuple((int(x) for x in torch.__version__.split(".")[:2]))
273 
274 
275 PT_BEFORE_1_7 = True
276 ver, has_ver = optional_import("pkg_resources", name="parse_version")
277 try:
278     if has_ver:
279         PT_BEFORE_1_7 = ver(torch.__version__) < ver("1.7")
280     else:
281         PT_BEFORE_1_7 = get_torch_version_tuple() < (1, 7)
282 except (AttributeError, TypeError):
283     pass
284
```
--- 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/monai/utils/module.py b/monai/utils/module.py
--- a/monai/utils/module.py
+++ b/monai/utils/module.py
@@ -96,11 +96,9 @@
     Returns True if the module's version is greater or equal to the 'min_version'.
     When min_version_str is not provided, it always returns True.
     """
-    if not min_version_str:
+    if not min_version_str or not hasattr(the_module, "__version__"):
         return True  # always valid version
-    if not hasattr(the_module, "__version__"):
-        warnings.warn(f"{the_module} has no attribute __version__ in min_version check.")
-        return True  # min_version is the default, shouldn't be noisy
+
     mod_version = tuple(int(x) for x in the_module.__version__.split(".")[:2])
     required = tuple(int(x) for x in min_version_str.split(".")[:2])
     return mod_version >= required

{"golden_diff": "diff --git a/monai/utils/module.py b/monai/utils/module.py\n--- a/monai/utils/module.py\n+++ b/monai/utils/module.py\n@@ -96,11 +96,9 @@\n     Returns True if the module's version is greater or equal to the 'min_version'.\n     When min_version_str is not provided, it always returns True.\n     \"\"\"\n-    if not min_version_str:\n+    if not min_version_str or not hasattr(the_module, \"__version__\"):\n         return True  # always valid version\n-    if not hasattr(the_module, \"__version__\"):\n-        warnings.warn(f\"{the_module} has no attribute __version__ in min_version check.\")\n-        return True  # min_version is the default, shouldn't be noisy\n+\n     mod_version = tuple(int(x) for x in the_module.__version__.split(\".\")[:2])\n     required = tuple(int(x) for x in min_version_str.split(\".\")[:2])\n     return mod_version >= required\n", "issue": "Always print warning message about min_package\n**Describe the bug**\r\n/opt/monai/monai/utils/module.py:100: UserWarning: <module 'pkg_resources' from '/opt/conda/lib/python3.8/site-packages/pkg_resources/__init__.py'> has no attribute __version__ in min_version check.\r\n  warnings.warn(f\"{the_module} has no attribute __version__ in min_version check.\")\r\n\n", "before_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\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#     http://www.apache.org/licenses/LICENSE-2.0\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\nimport inspect\nimport sys\nimport warnings\nfrom importlib import import_module\nfrom pkgutil import walk_packages\nfrom re import match\nfrom typing import Any, Callable, List, Sequence, Tuple, Union\n\nimport torch\n\nfrom .misc import ensure_tuple\n\nOPTIONAL_IMPORT_MSG_FMT = \"{}\"\n\n__all__ = [\n    \"InvalidPyTorchVersionError\",\n    \"OptionalImportError\",\n    \"exact_version\",\n    \"export\",\n    \"min_version\",\n    \"optional_import\",\n    \"load_submodules\",\n    \"get_full_type_name\",\n    \"has_option\",\n    \"get_package_version\",\n    \"get_torch_version_tuple\",\n    \"PT_BEFORE_1_7\",\n]\n\n\ndef export(modname):\n    \"\"\"\n    Make the decorated object a member of the named module. This will also add the object under its aliases if it has\n    a `__aliases__` member, thus this decorator should be before the `alias` decorator to pick up those names. Alias\n    names which conflict with package names or existing members will be ignored.\n    \"\"\"\n\n    def _inner(obj):\n        mod = import_module(modname)\n        if not hasattr(mod, obj.__name__):\n            setattr(mod, obj.__name__, obj)\n\n            # add the aliases for `obj` to the target module\n            for alias in getattr(obj, \"__aliases__\", ()):\n                if not hasattr(mod, alias):\n                    setattr(mod, alias, obj)\n\n        return obj\n\n    return _inner\n\n\ndef load_submodules(basemod, load_all: bool = True, exclude_pattern: str = \"(.*[tT]est.*)|(_.*)\"):\n    \"\"\"\n    Traverse the source of the module structure starting with module `basemod`, loading all packages plus all files if\n    `load_all` is True, excluding anything whose name matches `exclude_pattern`.\n    \"\"\"\n    submodules = []\n    err_mod: List[str] = []\n    for importer, name, is_pkg in walk_packages(\n        basemod.__path__, prefix=basemod.__name__ + \".\", onerror=err_mod.append\n    ):\n        if (is_pkg or load_all) and name not in sys.modules and match(exclude_pattern, name) is None:\n            try:\n                mod = import_module(name)\n                importer.find_module(name).load_module(name)  # type: ignore\n                submodules.append(mod)\n            except OptionalImportError:\n                pass  # could not import the optional deps., they are ignored\n\n    return submodules, err_mod\n\n\ndef get_full_type_name(typeobj):\n    module = typeobj.__module__\n    if module is None or module == str.__class__.__module__:\n        return typeobj.__name__  # Avoid reporting __builtin__\n    return module + \".\" + typeobj.__name__\n\n\ndef min_version(the_module, min_version_str: str = \"\") -> bool:\n    \"\"\"\n    Convert version strings into tuples of int and compare them.\n\n    Returns True if the module's version is greater or equal to the 'min_version'.\n    When min_version_str is not provided, it always returns True.\n    \"\"\"\n    if not min_version_str:\n        return True  # always valid version\n    if not hasattr(the_module, \"__version__\"):\n        warnings.warn(f\"{the_module} has no attribute __version__ in min_version check.\")\n        return True  # min_version is the default, shouldn't be noisy\n    mod_version = tuple(int(x) for x in the_module.__version__.split(\".\")[:2])\n    required = tuple(int(x) for x in min_version_str.split(\".\")[:2])\n    return mod_version >= required\n\n\ndef exact_version(the_module, version_str: str = \"\") -> bool:\n    \"\"\"\n    Returns True if the module's __version__ matches version_str\n    \"\"\"\n    if not hasattr(the_module, \"__version__\"):\n        warnings.warn(f\"{the_module} has no attribute __version__ in exact_version check.\")\n        return False\n    return bool(the_module.__version__ == version_str)\n\n\nclass InvalidPyTorchVersionError(Exception):\n    \"\"\"\n    Raised when called function or method requires a more recent\n    PyTorch version than that installed.\n    \"\"\"\n\n    def __init__(self, required_version, name):\n        message = f\"{name} requires PyTorch version {required_version} or later\"\n        super().__init__(message)\n\n\nclass OptionalImportError(ImportError):\n    \"\"\"\n    Could not import APIs from an optional dependency.\n    \"\"\"\n\n\ndef optional_import(\n    module: str,\n    version: str = \"\",\n    version_checker: Callable[..., bool] = min_version,\n    name: str = \"\",\n    descriptor: str = OPTIONAL_IMPORT_MSG_FMT,\n    version_args=None,\n    allow_namespace_pkg: bool = False,\n) -> Tuple[Any, bool]:\n    \"\"\"\n    Imports an optional module specified by `module` string.\n    Any importing related exceptions will be stored, and exceptions raise lazily\n    when attempting to use the failed-to-import module.\n\n    Args:\n        module: name of the module to be imported.\n        version: version string used by the version_checker.\n        version_checker: a callable to check the module version, Defaults to monai.utils.min_version.\n        name: a non-module attribute (such as method/class) to import from the imported module.\n        descriptor: a format string for the final error message when using a not imported module.\n        version_args: additional parameters to the version checker.\n        allow_namespace_pkg: whether importing a namespace package is allowed. Defaults to False.\n\n    Returns:\n        The imported module and a boolean flag indicating whether the import is successful.\n\n    Examples::\n\n        >>> torch, flag = optional_import('torch', '1.1')\n        >>> print(torch, flag)\n        <module 'torch' from 'python/lib/python3.6/site-packages/torch/__init__.py'> True\n\n        >>> the_module, flag = optional_import('unknown_module')\n        >>> print(flag)\n        False\n        >>> the_module.method  # trying to access a module which is not imported\n        OptionalImportError: import unknown_module (No module named 'unknown_module').\n\n        >>> torch, flag = optional_import('torch', '42', exact_version)\n        >>> torch.nn  # trying to access a module for which there isn't a proper version imported\n        OptionalImportError: import torch (requires version '42' by 'exact_version').\n\n        >>> conv, flag = optional_import('torch.nn.functional', '1.0', name='conv1d')\n        >>> print(conv)\n        <built-in method conv1d of type object at 0x11a49eac0>\n\n        >>> conv, flag = optional_import('torch.nn.functional', '42', name='conv1d')\n        >>> conv()  # trying to use a function from the not successfully imported module (due to unmatched version)\n        OptionalImportError: from torch.nn.functional import conv1d (requires version '42' by 'min_version').\n    \"\"\"\n\n    tb = None\n    exception_str = \"\"\n    if name:\n        actual_cmd = f\"from {module} import {name}\"\n    else:\n        actual_cmd = f\"import {module}\"\n    try:\n        pkg = __import__(module)  # top level module\n        the_module = import_module(module)\n        if not allow_namespace_pkg:\n            is_namespace = getattr(the_module, \"__file__\", None) is None and hasattr(the_module, \"__path__\")\n            if is_namespace:\n                raise AssertionError\n        if name:  # user specified to load class/function/... from the module\n            the_module = getattr(the_module, name)\n    except Exception as import_exception:  # any exceptions during import\n        tb = import_exception.__traceback__\n        exception_str = f\"{import_exception}\"\n    else:  # found the module\n        if version_args and version_checker(pkg, f\"{version}\", version_args):\n            return the_module, True\n        if not version_args and version_checker(pkg, f\"{version}\"):\n            return the_module, True\n\n    # preparing lazy error message\n    msg = descriptor.format(actual_cmd)\n    if version and tb is None:  # a pure version issue\n        msg += f\" (requires '{module} {version}' by '{version_checker.__name__}')\"\n    if exception_str:\n        msg += f\" ({exception_str})\"\n\n    class _LazyRaise:\n        def __init__(self, *_args, **_kwargs):\n            _default_msg = (\n                f\"{msg}.\"\n                + \"\\n\\nFor details about installing the optional dependencies, please visit:\"\n                + \"\\n    https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies\"\n            )\n            if tb is None:\n                self._exception = OptionalImportError(_default_msg)\n            else:\n                self._exception = OptionalImportError(_default_msg).with_traceback(tb)\n\n        def __getattr__(self, name):\n            \"\"\"\n            Raises:\n                OptionalImportError: When you call this method.\n            \"\"\"\n            raise self._exception\n\n        def __call__(self, *_args, **_kwargs):\n            \"\"\"\n            Raises:\n                OptionalImportError: When you call this method.\n            \"\"\"\n            raise self._exception\n\n    return _LazyRaise(), False\n\n\ndef has_option(obj, keywords: Union[str, Sequence[str]]) -> bool:\n    \"\"\"\n    Return a boolean indicating whether the given callable `obj` has the `keywords` in its signature.\n    \"\"\"\n    if not callable(obj):\n        return False\n    sig = inspect.signature(obj)\n    return all(key in sig.parameters for key in ensure_tuple(keywords))\n\n\ndef get_package_version(dep_name, default=\"NOT INSTALLED or UNKNOWN VERSION.\"):\n    \"\"\"\n    Try to load package and get version. If not found, return `default`.\n    \"\"\"\n    dep, has_dep = optional_import(dep_name)\n    if has_dep and hasattr(dep, \"__version__\"):\n        return dep.__version__\n    return default\n\n\ndef get_torch_version_tuple():\n    \"\"\"\n    Returns:\n        tuple of ints represents the pytorch major/minor version.\n    \"\"\"\n    return tuple((int(x) for x in torch.__version__.split(\".\")[:2]))\n\n\nPT_BEFORE_1_7 = True\nver, has_ver = optional_import(\"pkg_resources\", name=\"parse_version\")\ntry:\n    if has_ver:\n        PT_BEFORE_1_7 = ver(torch.__version__) < ver(\"1.7\")\n    else:\n        PT_BEFORE_1_7 = get_torch_version_tuple() < (1, 7)\nexcept (AttributeError, TypeError):\n    pass\n", "path": "monai/utils/module.py"}], "after_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\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#     http://www.apache.org/licenses/LICENSE-2.0\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\nimport inspect\nimport sys\nimport warnings\nfrom importlib import import_module\nfrom pkgutil import walk_packages\nfrom re import match\nfrom typing import Any, Callable, List, Sequence, Tuple, Union\n\nimport torch\n\nfrom .misc import ensure_tuple\n\nOPTIONAL_IMPORT_MSG_FMT = \"{}\"\n\n__all__ = [\n    \"InvalidPyTorchVersionError\",\n    \"OptionalImportError\",\n    \"exact_version\",\n    \"export\",\n    \"min_version\",\n    \"optional_import\",\n    \"load_submodules\",\n    \"get_full_type_name\",\n    \"has_option\",\n    \"get_package_version\",\n    \"get_torch_version_tuple\",\n    \"PT_BEFORE_1_7\",\n]\n\n\ndef export(modname):\n    \"\"\"\n    Make the decorated object a member of the named module. This will also add the object under its aliases if it has\n    a `__aliases__` member, thus this decorator should be before the `alias` decorator to pick up those names. Alias\n    names which conflict with package names or existing members will be ignored.\n    \"\"\"\n\n    def _inner(obj):\n        mod = import_module(modname)\n        if not hasattr(mod, obj.__name__):\n            setattr(mod, obj.__name__, obj)\n\n            # add the aliases for `obj` to the target module\n            for alias in getattr(obj, \"__aliases__\", ()):\n                if not hasattr(mod, alias):\n                    setattr(mod, alias, obj)\n\n        return obj\n\n    return _inner\n\n\ndef load_submodules(basemod, load_all: bool = True, exclude_pattern: str = \"(.*[tT]est.*)|(_.*)\"):\n    \"\"\"\n    Traverse the source of the module structure starting with module `basemod`, loading all packages plus all files if\n    `load_all` is True, excluding anything whose name matches `exclude_pattern`.\n    \"\"\"\n    submodules = []\n    err_mod: List[str] = []\n    for importer, name, is_pkg in walk_packages(\n        basemod.__path__, prefix=basemod.__name__ + \".\", onerror=err_mod.append\n    ):\n        if (is_pkg or load_all) and name not in sys.modules and match(exclude_pattern, name) is None:\n            try:\n                mod = import_module(name)\n                importer.find_module(name).load_module(name)  # type: ignore\n                submodules.append(mod)\n            except OptionalImportError:\n                pass  # could not import the optional deps., they are ignored\n\n    return submodules, err_mod\n\n\ndef get_full_type_name(typeobj):\n    module = typeobj.__module__\n    if module is None or module == str.__class__.__module__:\n        return typeobj.__name__  # Avoid reporting __builtin__\n    return module + \".\" + typeobj.__name__\n\n\ndef min_version(the_module, min_version_str: str = \"\") -> bool:\n    \"\"\"\n    Convert version strings into tuples of int and compare them.\n\n    Returns True if the module's version is greater or equal to the 'min_version'.\n    When min_version_str is not provided, it always returns True.\n    \"\"\"\n    if not min_version_str or not hasattr(the_module, \"__version__\"):\n        return True  # always valid version\n\n    mod_version = tuple(int(x) for x in the_module.__version__.split(\".\")[:2])\n    required = tuple(int(x) for x in min_version_str.split(\".\")[:2])\n    return mod_version >= required\n\n\ndef exact_version(the_module, version_str: str = \"\") -> bool:\n    \"\"\"\n    Returns True if the module's __version__ matches version_str\n    \"\"\"\n    if not hasattr(the_module, \"__version__\"):\n        warnings.warn(f\"{the_module} has no attribute __version__ in exact_version check.\")\n        return False\n    return bool(the_module.__version__ == version_str)\n\n\nclass InvalidPyTorchVersionError(Exception):\n    \"\"\"\n    Raised when called function or method requires a more recent\n    PyTorch version than that installed.\n    \"\"\"\n\n    def __init__(self, required_version, name):\n        message = f\"{name} requires PyTorch version {required_version} or later\"\n        super().__init__(message)\n\n\nclass OptionalImportError(ImportError):\n    \"\"\"\n    Could not import APIs from an optional dependency.\n    \"\"\"\n\n\ndef optional_import(\n    module: str,\n    version: str = \"\",\n    version_checker: Callable[..., bool] = min_version,\n    name: str = \"\",\n    descriptor: str = OPTIONAL_IMPORT_MSG_FMT,\n    version_args=None,\n    allow_namespace_pkg: bool = False,\n) -> Tuple[Any, bool]:\n    \"\"\"\n    Imports an optional module specified by `module` string.\n    Any importing related exceptions will be stored, and exceptions raise lazily\n    when attempting to use the failed-to-import module.\n\n    Args:\n        module: name of the module to be imported.\n        version: version string used by the version_checker.\n        version_checker: a callable to check the module version, Defaults to monai.utils.min_version.\n        name: a non-module attribute (such as method/class) to import from the imported module.\n        descriptor: a format string for the final error message when using a not imported module.\n        version_args: additional parameters to the version checker.\n        allow_namespace_pkg: whether importing a namespace package is allowed. Defaults to False.\n\n    Returns:\n        The imported module and a boolean flag indicating whether the import is successful.\n\n    Examples::\n\n        >>> torch, flag = optional_import('torch', '1.1')\n        >>> print(torch, flag)\n        <module 'torch' from 'python/lib/python3.6/site-packages/torch/__init__.py'> True\n\n        >>> the_module, flag = optional_import('unknown_module')\n        >>> print(flag)\n        False\n        >>> the_module.method  # trying to access a module which is not imported\n        OptionalImportError: import unknown_module (No module named 'unknown_module').\n\n        >>> torch, flag = optional_import('torch', '42', exact_version)\n        >>> torch.nn  # trying to access a module for which there isn't a proper version imported\n        OptionalImportError: import torch (requires version '42' by 'exact_version').\n\n        >>> conv, flag = optional_import('torch.nn.functional', '1.0', name='conv1d')\n        >>> print(conv)\n        <built-in method conv1d of type object at 0x11a49eac0>\n\n        >>> conv, flag = optional_import('torch.nn.functional', '42', name='conv1d')\n        >>> conv()  # trying to use a function from the not successfully imported module (due to unmatched version)\n        OptionalImportError: from torch.nn.functional import conv1d (requires version '42' by 'min_version').\n    \"\"\"\n\n    tb = None\n    exception_str = \"\"\n    if name:\n        actual_cmd = f\"from {module} import {name}\"\n    else:\n        actual_cmd = f\"import {module}\"\n    try:\n        pkg = __import__(module)  # top level module\n        the_module = import_module(module)\n        if not allow_namespace_pkg:\n            is_namespace = getattr(the_module, \"__file__\", None) is None and hasattr(the_module, \"__path__\")\n            if is_namespace:\n                raise AssertionError\n        if name:  # user specified to load class/function/... from the module\n            the_module = getattr(the_module, name)\n    except Exception as import_exception:  # any exceptions during import\n        tb = import_exception.__traceback__\n        exception_str = f\"{import_exception}\"\n    else:  # found the module\n        if version_args and version_checker(pkg, f\"{version}\", version_args):\n            return the_module, True\n        if not version_args and version_checker(pkg, f\"{version}\"):\n            return the_module, True\n\n    # preparing lazy error message\n    msg = descriptor.format(actual_cmd)\n    if version and tb is None:  # a pure version issue\n        msg += f\" (requires '{module} {version}' by '{version_checker.__name__}')\"\n    if exception_str:\n        msg += f\" ({exception_str})\"\n\n    class _LazyRaise:\n        def __init__(self, *_args, **_kwargs):\n            _default_msg = (\n                f\"{msg}.\"\n                + \"\\n\\nFor details about installing the optional dependencies, please visit:\"\n                + \"\\n    https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies\"\n            )\n            if tb is None:\n                self._exception = OptionalImportError(_default_msg)\n            else:\n                self._exception = OptionalImportError(_default_msg).with_traceback(tb)\n\n        def __getattr__(self, name):\n            \"\"\"\n            Raises:\n                OptionalImportError: When you call this method.\n            \"\"\"\n            raise self._exception\n\n        def __call__(self, *_args, **_kwargs):\n            \"\"\"\n            Raises:\n                OptionalImportError: When you call this method.\n            \"\"\"\n            raise self._exception\n\n    return _LazyRaise(), False\n\n\ndef has_option(obj, keywords: Union[str, Sequence[str]]) -> bool:\n    \"\"\"\n    Return a boolean indicating whether the given callable `obj` has the `keywords` in its signature.\n    \"\"\"\n    if not callable(obj):\n        return False\n    sig = inspect.signature(obj)\n    return all(key in sig.parameters for key in ensure_tuple(keywords))\n\n\ndef get_package_version(dep_name, default=\"NOT INSTALLED or UNKNOWN VERSION.\"):\n    \"\"\"\n    Try to load package and get version. If not found, return `default`.\n    \"\"\"\n    dep, has_dep = optional_import(dep_name)\n    if has_dep and hasattr(dep, \"__version__\"):\n        return dep.__version__\n    return default\n\n\ndef get_torch_version_tuple():\n    \"\"\"\n    Returns:\n        tuple of ints represents the pytorch major/minor version.\n    \"\"\"\n    return tuple((int(x) for x in torch.__version__.split(\".\")[:2]))\n\n\nPT_BEFORE_1_7 = True\nver, has_ver = optional_import(\"pkg_resources\", name=\"parse_version\")\ntry:\n    if has_ver:\n        PT_BEFORE_1_7 = ver(torch.__version__) < ver(\"1.7\")\n    else:\n        PT_BEFORE_1_7 = get_torch_version_tuple() < (1, 7)\nexcept (AttributeError, TypeError):\n    pass\n", "path": "monai/utils/module.py"}]}