We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add ability to load multiple libs in one call
## Description
`sy.load()` should accept any valid sequence of strings, variadic args, a list, tuple or set of strings like:
```
sy.load("pydp", "opacus")
sy.load(["pydp", "opacus"])
sy.load(("pydp", "opacus"))
sy.load({"pydp", "opacus"})
```

## Definition of Done
Loading multiple libs in one go is possible with tests to show it works.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/syft/lib/__init__.py`
Content:
```
1 # stdlib
2 import importlib
3 import sys
4 from types import ModuleType
5 from typing import Any
6 from typing import Any as TypeAny
7 from typing import Dict as TypeDict
8 from typing import Optional
9 from typing import Union as TypeUnion
10 import warnings
11 
12 # third party
13 from packaging import version
14 
15 # syft relative
16 from ..ast.globals import Globals
17 from ..core.node.abstract.node import AbstractNodeClient
18 from ..lib.plan import create_plan_ast
19 from ..lib.python import create_python_ast
20 from ..lib.remote_dataloader import create_remote_dataloader_ast
21 from ..lib.torch import create_torch_ast
22 from ..lib.torchvision import create_torchvision_ast
23 from ..logger import critical
24 from ..logger import traceback_and_raise
25 from ..logger import warning
26 from .misc import create_union_ast
27 
28 
29 class VendorLibraryImportException(Exception):
30     pass
31 
32 
33 def vendor_requirements_available(vendor_requirements: TypeDict[str, TypeAny]) -> bool:
34     """
35     Check whether torch or python version is supported
36 
37     Args:
38         vendor_requirements: dictionary containing version of python or torch to be supported
39 
40     Returns:
41         True if system supports all vendor requirements
42 
43     """
44     # see if python version is supported
45     if "python" in vendor_requirements:
46         python_reqs = vendor_requirements["python"]
47 
48         PYTHON_VERSION = sys.version_info
49         min_version = python_reqs.get("min_version", None)
50         if min_version is not None:
51             if PYTHON_VERSION < min_version:
52                 traceback_and_raise(
53                     VendorLibraryImportException(
54                         f"Unable to load {vendor_requirements['lib']}."
55                         + f"Python: {PYTHON_VERSION} < {min_version}"
56                     )
57                 )
58         max_version = python_reqs.get("max_version", None)
59         if max_version is not None:
60             if PYTHON_VERSION > max_version:
61                 traceback_and_raise(
62                     VendorLibraryImportException(
63                         f"Unable to load {vendor_requirements['lib']}."
64                         + f"Python: {PYTHON_VERSION} > {max_version}"
65                     )
66                 )
67 
68     # see if torch version is supported
69     if "torch" in vendor_requirements:
70         torch_reqs = vendor_requirements["torch"]
71         # third party
72         import torch
73 
74         TORCH_VERSION = version.parse(torch.__version__.split("+")[0])
75         min_version = torch_reqs.get("min_version", None)
76         if min_version is not None:
77             if TORCH_VERSION < version.parse(min_version):
78                 traceback_and_raise(
79                     VendorLibraryImportException(
80                         f"Unable to load {vendor_requirements['lib']}."
81                         + f"Torch: {TORCH_VERSION} < {min_version}"
82                     )
83                 )
84 
85         max_version = torch_reqs.get("max_version", None)
86         if max_version is not None:
87             if TORCH_VERSION > version.parse(max_version):
88                 traceback_and_raise(
89                     VendorLibraryImportException(
90                         f"Unable to load {vendor_requirements['lib']}."
91                         + f"Torch: {TORCH_VERSION} > {max_version}"
92                     )
93                 )
94 
95     return True
96 
97 
98 def _add_lib(
99     *, vendor_ast: ModuleType, ast_or_client: TypeUnion[Globals, AbstractNodeClient]
100 ) -> None:
101     update_ast = getattr(vendor_ast, "update_ast", None)
102     post_update_ast = getattr(vendor_ast, "post_update_ast", None)
103     if update_ast is not None:
104         update_ast(ast_or_client=ast_or_client)
105         if post_update_ast is not None:
106             post_update_ast(ast_or_client=ast_or_client)
107 
108 
109 def _regenerate_unions(*, lib_ast: Globals, client: TypeAny = None) -> None:
110     union_misc_ast = getattr(
111         getattr(create_union_ast(lib_ast=lib_ast, client=client), "syft"), "lib"
112     )
113     if client is not None:
114         client.syft.lib.add_attr(attr_name="misc", attr=union_misc_ast.attrs["misc"])
115     else:
116         lib_ast.syft.lib.add_attr(attr_name="misc", attr=union_misc_ast.attrs["misc"])
117 
118 
119 def _load_lib(*, lib: str, options: TypeDict[str, TypeAny] = {}) -> None:
120     """
121     Load and Update Node with given library module
122 
123     Args:
124         lib: name of library to load and update Node with
125         options: external requirements for loading library successfully
126     """
127     _ = importlib.import_module(lib)
128     vendor_ast = importlib.import_module(f"syft.lib.{lib}")
129     PACKAGE_SUPPORT = getattr(vendor_ast, "PACKAGE_SUPPORT", None)
130     PACKAGE_SUPPORT.update(options)
131     if PACKAGE_SUPPORT is not None and vendor_requirements_available(
132         vendor_requirements=PACKAGE_SUPPORT
133     ):
134         global lib_ast
135         _add_lib(vendor_ast=vendor_ast, ast_or_client=lib_ast)
136         # cache the constructor for future created clients
137         lib_ast.loaded_lib_constructors[lib] = getattr(vendor_ast, "update_ast", None)
138         _regenerate_unions(lib_ast=lib_ast)
139 
140         for _, client in lib_ast.registered_clients.items():
141             _add_lib(vendor_ast=vendor_ast, ast_or_client=client)
142             _regenerate_unions(lib_ast=lib_ast, client=client)
143 
144 
145 def load(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:
146     """
147     Load and Update Node with given library module
148 
149     Args:
150         lib: name of library to load and update Node with
151         options: external requirements for loading library successfully
152     """
153     try:
154         _load_lib(lib=lib, options=options)
155     except VendorLibraryImportException as e:
156         critical(e)
157     except Exception as e:
158         critical(f"Unable to load package support for: {lib}. {e}")
159 
160 
161 def load_lib(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:
162     """
163     Load and Update Node with given library module
164     load_lib() is deprecated please use load() in the future
165 
166     Args:
167         lib: name of library to load and update Node with
168         options: external requirements for loading library successfully
169 
170     """
171     msg = "load_lib() is deprecated please use load() in the future"
172     warning(msg, print=True)
173     warnings.warn(msg, DeprecationWarning)
174     load(lib=lib, options=options)
175 
176 
177 # now we need to load the relevant frameworks onto the node
178 def create_lib_ast(client: Optional[Any] = None) -> Globals:
179     """
180     Create AST and load the relevant frameworks onto the node
181 
182     Args:
183         client: VM client onto whom the frameworks need to be loaded
184 
185     Returns:
186         AST for client of type Globals
187 
188     """
189     python_ast = create_python_ast(client=client)
190     torch_ast = create_torch_ast(client=client)
191     torchvision_ast = create_torchvision_ast(client=client)
192     # numpy_ast = create_numpy_ast()
193     plan_ast = create_plan_ast(client=client)
194     remote_dataloader_ast = create_remote_dataloader_ast(client=client)
195 
196     lib_ast = Globals(client=client)
197     lib_ast.add_attr(attr_name="syft", attr=python_ast.attrs["syft"])
198     lib_ast.add_attr(attr_name="torch", attr=torch_ast.attrs["torch"])
199     lib_ast.add_attr(attr_name="torchvision", attr=torchvision_ast.attrs["torchvision"])
200     lib_ast.syft.add_attr("core", attr=plan_ast.syft.core)
201     lib_ast.syft.core.add_attr(
202         "remote_dataloader", remote_dataloader_ast.syft.core.remote_dataloader
203     )
204 
205     # let the misc creation be always the last, as it needs the full ast solved
206     # to properly generated unions
207     union_misc_ast = getattr(getattr(create_union_ast(lib_ast, client), "syft"), "lib")
208     lib_ast.syft.lib.add_attr(attr_name="misc", attr=union_misc_ast.attrs["misc"])
209 
210     return lib_ast
211 
212 
213 lib_ast = create_lib_ast(None)
214
```
--- 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/src/syft/lib/__init__.py b/src/syft/lib/__init__.py
--- a/src/syft/lib/__init__.py
+++ b/src/syft/lib/__init__.py
@@ -5,7 +5,11 @@
 from typing import Any
 from typing import Any as TypeAny
 from typing import Dict as TypeDict
+from typing import Iterable
+from typing import List as TypeList
 from typing import Optional
+from typing import Set as TypeSet
+from typing import Tuple as TypeTuple
 from typing import Union as TypeUnion
 import warnings
 
@@ -142,20 +146,42 @@
             _regenerate_unions(lib_ast=lib_ast, client=client)
 
 
-def load(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:
+def load(
+    *libs: TypeUnion[TypeList[str], TypeTuple[str], TypeSet[str], str],
+    options: TypeDict[str, TypeAny] = {},
+    **kwargs: str,
+) -> None:
     """
     Load and Update Node with given library module
 
     Args:
-        lib: name of library to load and update Node with
+        *libs: names of libraries to load and update Node with (can be variadic, tuple, list, set)
         options: external requirements for loading library successfully
+        **kwargs: for backward compatibility with calls like `syft.load(lib = "opacus")`
     """
-    try:
-        _load_lib(lib=lib, options=options)
-    except VendorLibraryImportException as e:
-        critical(e)
-    except Exception as e:
-        critical(f"Unable to load package support for: {lib}. {e}")
+    # For backward compatibility with calls like `syft.load(lib = "opacus")`
+    if "lib" in kwargs.keys():
+        libs += tuple(kwargs["lib"])
+
+    if isinstance(libs[0], Iterable):
+        if not isinstance(libs[0], str):
+            libs = tuple(libs[0])
+        for lib in libs:
+            if isinstance(lib, str):
+                try:
+                    _load_lib(lib=str(lib), options=options)
+                except VendorLibraryImportException as e:
+                    critical(e)
+                except Exception as e:
+                    critical(f"Unable to load package support for: {lib}. {e}")
+            else:
+                critical(
+                    f"Unable to load package support for: {lib}. Pass lib name as string object."
+                )
+    else:
+        critical(
+            "Unable to load package support for any library. Iterable object not found."
+        )
 
 
 def load_lib(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:

{"golden_diff": "diff --git a/src/syft/lib/__init__.py b/src/syft/lib/__init__.py\n--- a/src/syft/lib/__init__.py\n+++ b/src/syft/lib/__init__.py\n@@ -5,7 +5,11 @@\n from typing import Any\n from typing import Any as TypeAny\n from typing import Dict as TypeDict\n+from typing import Iterable\n+from typing import List as TypeList\n from typing import Optional\n+from typing import Set as TypeSet\n+from typing import Tuple as TypeTuple\n from typing import Union as TypeUnion\n import warnings\n \n@@ -142,20 +146,42 @@\n             _regenerate_unions(lib_ast=lib_ast, client=client)\n \n \n-def load(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:\n+def load(\n+    *libs: TypeUnion[TypeList[str], TypeTuple[str], TypeSet[str], str],\n+    options: TypeDict[str, TypeAny] = {},\n+    **kwargs: str,\n+) -> None:\n     \"\"\"\n     Load and Update Node with given library module\n \n     Args:\n-        lib: name of library to load and update Node with\n+        *libs: names of libraries to load and update Node with (can be variadic, tuple, list, set)\n         options: external requirements for loading library successfully\n+        **kwargs: for backward compatibility with calls like `syft.load(lib = \"opacus\")`\n     \"\"\"\n-    try:\n-        _load_lib(lib=lib, options=options)\n-    except VendorLibraryImportException as e:\n-        critical(e)\n-    except Exception as e:\n-        critical(f\"Unable to load package support for: {lib}. {e}\")\n+    # For backward compatibility with calls like `syft.load(lib = \"opacus\")`\n+    if \"lib\" in kwargs.keys():\n+        libs += tuple(kwargs[\"lib\"])\n+\n+    if isinstance(libs[0], Iterable):\n+        if not isinstance(libs[0], str):\n+            libs = tuple(libs[0])\n+        for lib in libs:\n+            if isinstance(lib, str):\n+                try:\n+                    _load_lib(lib=str(lib), options=options)\n+                except VendorLibraryImportException as e:\n+                    critical(e)\n+                except Exception as e:\n+                    critical(f\"Unable to load package support for: {lib}. {e}\")\n+            else:\n+                critical(\n+                    f\"Unable to load package support for: {lib}. Pass lib name as string object.\"\n+                )\n+    else:\n+        critical(\n+            \"Unable to load package support for any library. Iterable object not found.\"\n+        )\n \n \n def load_lib(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:\n", "issue": "Add ability to load multiple libs in one call\n## Description\r\n`sy.load()` should accept any valid sequence of strings, variadic args, a list, tuple or set of strings like:\r\n```\r\nsy.load(\"pydp\", \"opacus\")\r\nsy.load([\"pydp\", \"opacus\"])\r\nsy.load((\"pydp\", \"opacus\"))\r\nsy.load({\"pydp\", \"opacus\"})\r\n```\r\n\r\n## Definition of Done\r\nLoading multiple libs in one go is possible with tests to show it works.\n", "before_files": [{"content": "# stdlib\nimport importlib\nimport sys\nfrom types import ModuleType\nfrom typing import Any\nfrom typing import Any as TypeAny\nfrom typing import Dict as TypeDict\nfrom typing import Optional\nfrom typing import Union as TypeUnion\nimport warnings\n\n# third party\nfrom packaging import version\n\n# syft relative\nfrom ..ast.globals import Globals\nfrom ..core.node.abstract.node import AbstractNodeClient\nfrom ..lib.plan import create_plan_ast\nfrom ..lib.python import create_python_ast\nfrom ..lib.remote_dataloader import create_remote_dataloader_ast\nfrom ..lib.torch import create_torch_ast\nfrom ..lib.torchvision import create_torchvision_ast\nfrom ..logger import critical\nfrom ..logger import traceback_and_raise\nfrom ..logger import warning\nfrom .misc import create_union_ast\n\n\nclass VendorLibraryImportException(Exception):\n    pass\n\n\ndef vendor_requirements_available(vendor_requirements: TypeDict[str, TypeAny]) -> bool:\n    \"\"\"\n    Check whether torch or python version is supported\n\n    Args:\n        vendor_requirements: dictionary containing version of python or torch to be supported\n\n    Returns:\n        True if system supports all vendor requirements\n\n    \"\"\"\n    # see if python version is supported\n    if \"python\" in vendor_requirements:\n        python_reqs = vendor_requirements[\"python\"]\n\n        PYTHON_VERSION = sys.version_info\n        min_version = python_reqs.get(\"min_version\", None)\n        if min_version is not None:\n            if PYTHON_VERSION < min_version:\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Python: {PYTHON_VERSION} < {min_version}\"\n                    )\n                )\n        max_version = python_reqs.get(\"max_version\", None)\n        if max_version is not None:\n            if PYTHON_VERSION > max_version:\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Python: {PYTHON_VERSION} > {max_version}\"\n                    )\n                )\n\n    # see if torch version is supported\n    if \"torch\" in vendor_requirements:\n        torch_reqs = vendor_requirements[\"torch\"]\n        # third party\n        import torch\n\n        TORCH_VERSION = version.parse(torch.__version__.split(\"+\")[0])\n        min_version = torch_reqs.get(\"min_version\", None)\n        if min_version is not None:\n            if TORCH_VERSION < version.parse(min_version):\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Torch: {TORCH_VERSION} < {min_version}\"\n                    )\n                )\n\n        max_version = torch_reqs.get(\"max_version\", None)\n        if max_version is not None:\n            if TORCH_VERSION > version.parse(max_version):\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Torch: {TORCH_VERSION} > {max_version}\"\n                    )\n                )\n\n    return True\n\n\ndef _add_lib(\n    *, vendor_ast: ModuleType, ast_or_client: TypeUnion[Globals, AbstractNodeClient]\n) -> None:\n    update_ast = getattr(vendor_ast, \"update_ast\", None)\n    post_update_ast = getattr(vendor_ast, \"post_update_ast\", None)\n    if update_ast is not None:\n        update_ast(ast_or_client=ast_or_client)\n        if post_update_ast is not None:\n            post_update_ast(ast_or_client=ast_or_client)\n\n\ndef _regenerate_unions(*, lib_ast: Globals, client: TypeAny = None) -> None:\n    union_misc_ast = getattr(\n        getattr(create_union_ast(lib_ast=lib_ast, client=client), \"syft\"), \"lib\"\n    )\n    if client is not None:\n        client.syft.lib.add_attr(attr_name=\"misc\", attr=union_misc_ast.attrs[\"misc\"])\n    else:\n        lib_ast.syft.lib.add_attr(attr_name=\"misc\", attr=union_misc_ast.attrs[\"misc\"])\n\n\ndef _load_lib(*, lib: str, options: TypeDict[str, TypeAny] = {}) -> None:\n    \"\"\"\n    Load and Update Node with given library module\n\n    Args:\n        lib: name of library to load and update Node with\n        options: external requirements for loading library successfully\n    \"\"\"\n    _ = importlib.import_module(lib)\n    vendor_ast = importlib.import_module(f\"syft.lib.{lib}\")\n    PACKAGE_SUPPORT = getattr(vendor_ast, \"PACKAGE_SUPPORT\", None)\n    PACKAGE_SUPPORT.update(options)\n    if PACKAGE_SUPPORT is not None and vendor_requirements_available(\n        vendor_requirements=PACKAGE_SUPPORT\n    ):\n        global lib_ast\n        _add_lib(vendor_ast=vendor_ast, ast_or_client=lib_ast)\n        # cache the constructor for future created clients\n        lib_ast.loaded_lib_constructors[lib] = getattr(vendor_ast, \"update_ast\", None)\n        _regenerate_unions(lib_ast=lib_ast)\n\n        for _, client in lib_ast.registered_clients.items():\n            _add_lib(vendor_ast=vendor_ast, ast_or_client=client)\n            _regenerate_unions(lib_ast=lib_ast, client=client)\n\n\ndef load(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:\n    \"\"\"\n    Load and Update Node with given library module\n\n    Args:\n        lib: name of library to load and update Node with\n        options: external requirements for loading library successfully\n    \"\"\"\n    try:\n        _load_lib(lib=lib, options=options)\n    except VendorLibraryImportException as e:\n        critical(e)\n    except Exception as e:\n        critical(f\"Unable to load package support for: {lib}. {e}\")\n\n\ndef load_lib(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:\n    \"\"\"\n    Load and Update Node with given library module\n    load_lib() is deprecated please use load() in the future\n\n    Args:\n        lib: name of library to load and update Node with\n        options: external requirements for loading library successfully\n\n    \"\"\"\n    msg = \"load_lib() is deprecated please use load() in the future\"\n    warning(msg, print=True)\n    warnings.warn(msg, DeprecationWarning)\n    load(lib=lib, options=options)\n\n\n# now we need to load the relevant frameworks onto the node\ndef create_lib_ast(client: Optional[Any] = None) -> Globals:\n    \"\"\"\n    Create AST and load the relevant frameworks onto the node\n\n    Args:\n        client: VM client onto whom the frameworks need to be loaded\n\n    Returns:\n        AST for client of type Globals\n\n    \"\"\"\n    python_ast = create_python_ast(client=client)\n    torch_ast = create_torch_ast(client=client)\n    torchvision_ast = create_torchvision_ast(client=client)\n    # numpy_ast = create_numpy_ast()\n    plan_ast = create_plan_ast(client=client)\n    remote_dataloader_ast = create_remote_dataloader_ast(client=client)\n\n    lib_ast = Globals(client=client)\n    lib_ast.add_attr(attr_name=\"syft\", attr=python_ast.attrs[\"syft\"])\n    lib_ast.add_attr(attr_name=\"torch\", attr=torch_ast.attrs[\"torch\"])\n    lib_ast.add_attr(attr_name=\"torchvision\", attr=torchvision_ast.attrs[\"torchvision\"])\n    lib_ast.syft.add_attr(\"core\", attr=plan_ast.syft.core)\n    lib_ast.syft.core.add_attr(\n        \"remote_dataloader\", remote_dataloader_ast.syft.core.remote_dataloader\n    )\n\n    # let the misc creation be always the last, as it needs the full ast solved\n    # to properly generated unions\n    union_misc_ast = getattr(getattr(create_union_ast(lib_ast, client), \"syft\"), \"lib\")\n    lib_ast.syft.lib.add_attr(attr_name=\"misc\", attr=union_misc_ast.attrs[\"misc\"])\n\n    return lib_ast\n\n\nlib_ast = create_lib_ast(None)\n", "path": "src/syft/lib/__init__.py"}], "after_files": [{"content": "# stdlib\nimport importlib\nimport sys\nfrom types import ModuleType\nfrom typing import Any\nfrom typing import Any as TypeAny\nfrom typing import Dict as TypeDict\nfrom typing import Iterable\nfrom typing import List as TypeList\nfrom typing import Optional\nfrom typing import Set as TypeSet\nfrom typing import Tuple as TypeTuple\nfrom typing import Union as TypeUnion\nimport warnings\n\n# third party\nfrom packaging import version\n\n# syft relative\nfrom ..ast.globals import Globals\nfrom ..core.node.abstract.node import AbstractNodeClient\nfrom ..lib.plan import create_plan_ast\nfrom ..lib.python import create_python_ast\nfrom ..lib.remote_dataloader import create_remote_dataloader_ast\nfrom ..lib.torch import create_torch_ast\nfrom ..lib.torchvision import create_torchvision_ast\nfrom ..logger import critical\nfrom ..logger import traceback_and_raise\nfrom ..logger import warning\nfrom .misc import create_union_ast\n\n\nclass VendorLibraryImportException(Exception):\n    pass\n\n\ndef vendor_requirements_available(vendor_requirements: TypeDict[str, TypeAny]) -> bool:\n    \"\"\"\n    Check whether torch or python version is supported\n\n    Args:\n        vendor_requirements: dictionary containing version of python or torch to be supported\n\n    Returns:\n        True if system supports all vendor requirements\n\n    \"\"\"\n    # see if python version is supported\n    if \"python\" in vendor_requirements:\n        python_reqs = vendor_requirements[\"python\"]\n\n        PYTHON_VERSION = sys.version_info\n        min_version = python_reqs.get(\"min_version\", None)\n        if min_version is not None:\n            if PYTHON_VERSION < min_version:\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Python: {PYTHON_VERSION} < {min_version}\"\n                    )\n                )\n        max_version = python_reqs.get(\"max_version\", None)\n        if max_version is not None:\n            if PYTHON_VERSION > max_version:\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Python: {PYTHON_VERSION} > {max_version}\"\n                    )\n                )\n\n    # see if torch version is supported\n    if \"torch\" in vendor_requirements:\n        torch_reqs = vendor_requirements[\"torch\"]\n        # third party\n        import torch\n\n        TORCH_VERSION = version.parse(torch.__version__.split(\"+\")[0])\n        min_version = torch_reqs.get(\"min_version\", None)\n        if min_version is not None:\n            if TORCH_VERSION < version.parse(min_version):\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Torch: {TORCH_VERSION} < {min_version}\"\n                    )\n                )\n\n        max_version = torch_reqs.get(\"max_version\", None)\n        if max_version is not None:\n            if TORCH_VERSION > version.parse(max_version):\n                traceback_and_raise(\n                    VendorLibraryImportException(\n                        f\"Unable to load {vendor_requirements['lib']}.\"\n                        + f\"Torch: {TORCH_VERSION} > {max_version}\"\n                    )\n                )\n\n    return True\n\n\ndef _add_lib(\n    *, vendor_ast: ModuleType, ast_or_client: TypeUnion[Globals, AbstractNodeClient]\n) -> None:\n    update_ast = getattr(vendor_ast, \"update_ast\", None)\n    post_update_ast = getattr(vendor_ast, \"post_update_ast\", None)\n    if update_ast is not None:\n        update_ast(ast_or_client=ast_or_client)\n        if post_update_ast is not None:\n            post_update_ast(ast_or_client=ast_or_client)\n\n\ndef _regenerate_unions(*, lib_ast: Globals, client: TypeAny = None) -> None:\n    union_misc_ast = getattr(\n        getattr(create_union_ast(lib_ast=lib_ast, client=client), \"syft\"), \"lib\"\n    )\n    if client is not None:\n        client.syft.lib.add_attr(attr_name=\"misc\", attr=union_misc_ast.attrs[\"misc\"])\n    else:\n        lib_ast.syft.lib.add_attr(attr_name=\"misc\", attr=union_misc_ast.attrs[\"misc\"])\n\n\ndef _load_lib(*, lib: str, options: TypeDict[str, TypeAny] = {}) -> None:\n    \"\"\"\n    Load and Update Node with given library module\n\n    Args:\n        lib: name of library to load and update Node with\n        options: external requirements for loading library successfully\n    \"\"\"\n    _ = importlib.import_module(lib)\n    vendor_ast = importlib.import_module(f\"syft.lib.{lib}\")\n    PACKAGE_SUPPORT = getattr(vendor_ast, \"PACKAGE_SUPPORT\", None)\n    PACKAGE_SUPPORT.update(options)\n    if PACKAGE_SUPPORT is not None and vendor_requirements_available(\n        vendor_requirements=PACKAGE_SUPPORT\n    ):\n        global lib_ast\n        _add_lib(vendor_ast=vendor_ast, ast_or_client=lib_ast)\n        # cache the constructor for future created clients\n        lib_ast.loaded_lib_constructors[lib] = getattr(vendor_ast, \"update_ast\", None)\n        _regenerate_unions(lib_ast=lib_ast)\n\n        for _, client in lib_ast.registered_clients.items():\n            _add_lib(vendor_ast=vendor_ast, ast_or_client=client)\n            _regenerate_unions(lib_ast=lib_ast, client=client)\n\n\ndef load(\n    *libs: TypeUnion[TypeList[str], TypeTuple[str], TypeSet[str], str],\n    options: TypeDict[str, TypeAny] = {},\n    **kwargs: str,\n) -> None:\n    \"\"\"\n    Load and Update Node with given library module\n\n    Args:\n        *libs: names of libraries to load and update Node with (can be variadic, tuple, list, set)\n        options: external requirements for loading library successfully\n        **kwargs: for backward compatibility with calls like `syft.load(lib = \"opacus\")`\n    \"\"\"\n    # For backward compatibility with calls like `syft.load(lib = \"opacus\")`\n    if \"lib\" in kwargs.keys():\n        libs += tuple(kwargs[\"lib\"])\n\n    if isinstance(libs[0], Iterable):\n        if not isinstance(libs[0], str):\n            libs = tuple(libs[0])\n        for lib in libs:\n            if isinstance(lib, str):\n                try:\n                    _load_lib(lib=str(lib), options=options)\n                except VendorLibraryImportException as e:\n                    critical(e)\n                except Exception as e:\n                    critical(f\"Unable to load package support for: {lib}. {e}\")\n            else:\n                critical(\n                    f\"Unable to load package support for: {lib}. Pass lib name as string object.\"\n                )\n    else:\n        critical(\n            \"Unable to load package support for any library. Iterable object not found.\"\n        )\n\n\ndef load_lib(lib: str, options: TypeDict[str, TypeAny] = {}) -> None:\n    \"\"\"\n    Load and Update Node with given library module\n    load_lib() is deprecated please use load() in the future\n\n    Args:\n        lib: name of library to load and update Node with\n        options: external requirements for loading library successfully\n\n    \"\"\"\n    msg = \"load_lib() is deprecated please use load() in the future\"\n    warning(msg, print=True)\n    warnings.warn(msg, DeprecationWarning)\n    load(lib=lib, options=options)\n\n\n# now we need to load the relevant frameworks onto the node\ndef create_lib_ast(client: Optional[Any] = None) -> Globals:\n    \"\"\"\n    Create AST and load the relevant frameworks onto the node\n\n    Args:\n        client: VM client onto whom the frameworks need to be loaded\n\n    Returns:\n        AST for client of type Globals\n\n    \"\"\"\n    python_ast = create_python_ast(client=client)\n    torch_ast = create_torch_ast(client=client)\n    torchvision_ast = create_torchvision_ast(client=client)\n    # numpy_ast = create_numpy_ast()\n    plan_ast = create_plan_ast(client=client)\n    remote_dataloader_ast = create_remote_dataloader_ast(client=client)\n\n    lib_ast = Globals(client=client)\n    lib_ast.add_attr(attr_name=\"syft\", attr=python_ast.attrs[\"syft\"])\n    lib_ast.add_attr(attr_name=\"torch\", attr=torch_ast.attrs[\"torch\"])\n    lib_ast.add_attr(attr_name=\"torchvision\", attr=torchvision_ast.attrs[\"torchvision\"])\n    lib_ast.syft.add_attr(\"core\", attr=plan_ast.syft.core)\n    lib_ast.syft.core.add_attr(\n        \"remote_dataloader\", remote_dataloader_ast.syft.core.remote_dataloader\n    )\n\n    # let the misc creation be always the last, as it needs the full ast solved\n    # to properly generated unions\n    union_misc_ast = getattr(getattr(create_union_ast(lib_ast, client), \"syft\"), \"lib\")\n    lib_ast.syft.lib.add_attr(attr_name=\"misc\", attr=union_misc_ast.attrs[\"misc\"])\n\n    return lib_ast\n\n\nlib_ast = create_lib_ast(None)\n", "path": "src/syft/lib/__init__.py"}]}