prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  if/elif statement without else clause in `FullModelShareableGenerator`
  It would be helpful to add an else statement with a warning message that this DataKind is not supported. I ran into this issue when sending a DataKind.COLLECTION with the shareable by mistake.
  
  See https://github.com/NVIDIA/NVFlare/blob/b3ff7844a9bef746218527ccd07601feb66fd94c/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py#L61
  
  In the same class, when sending a DXO instead of Shareable type, I got this error
  
  ```
  Traceback (most recent call last):
    File "/home/hroth/Code/nvflare/hroth-agglib/nvflare/app_common/workflows/scatter_and_gather.py", line 202, in control_flow
      self._global_weights = self.shareable_gen.shareable_to_learnable(aggr_result, fl_ctx)
    File "/home/hroth/Code/nvflare/hroth-agglib/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py", line 54, in shareable_to_learnable
      dxo = from_shareable(shareable)
    File "/home/hroth/Code/nvflare/hroth-agglib/nvflare/apis/dxo.py", line 120, in from_shareable
      content_type = s.get_header(ReservedHeaderKey.CONTENT_TYPE)
  AttributeError: 'DXO' object has no attribute 'get_header'
  ```
  There should be an instance check here https://github.com/NVIDIA/NVFlare/blob/b3ff7844a9bef746218527ccd07601feb66fd94c/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py#L54
  
  
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `nvflare/app_common/shareablegenerators/full_model_shareable_generator.py`
  Content:
  ```
  1 # Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
  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 nvflare.apis.dxo import DataKind, from_shareable
  16 from nvflare.apis.fl_context import FLContext
  17 from nvflare.apis.shareable import Shareable
  18 from nvflare.app_common.abstract.model import ModelLearnable, ModelLearnableKey, model_learnable_to_dxo
  19 from nvflare.app_common.abstract.shareable_generator import ShareableGenerator
  20 from nvflare.app_common.app_constant import AppConstants
  21 
  22 
  23 class FullModelShareableGenerator(ShareableGenerator):
  24     def learnable_to_shareable(self, ml: ModelLearnable, fl_ctx: FLContext) -> Shareable:
  25         """Convert Learnable to Shareable.
  26 
  27         Args:
  28             model (Learnable): model to be converted
  29             fl_ctx (FLContext): FL context
  30 
  31         Returns:
  32             Shareable: a shareable containing a DXO object,
  33         """
  34         dxo = model_learnable_to_dxo(ml)
  35         return dxo.to_shareable()
  36 
  37     def shareable_to_learnable(self, shareable: Shareable, fl_ctx: FLContext) -> ModelLearnable:
  38         """Convert Shareable to Learnable.
  39 
  40         Supporting TYPE == TYPE_WEIGHT_DIFF or TYPE_WEIGHTS
  41 
  42         Args:
  43             shareable (Shareable): Shareable that contains a DXO object
  44             fl_ctx (FLContext): FL context
  45 
  46         Returns: a ModelLearnable object
  47         """
  48         base_model = fl_ctx.get_prop(AppConstants.GLOBAL_MODEL)
  49         if not base_model:
  50             self.system_panic(reason="No global base model!", fl_ctx=fl_ctx)
  51             return base_model
  52 
  53         weights = base_model[ModelLearnableKey.WEIGHTS]
  54         dxo = from_shareable(shareable)
  55 
  56         if dxo.data_kind == DataKind.WEIGHT_DIFF:
  57             if dxo.data is not None:
  58                 model_diff = dxo.data
  59                 for v_name, v_value in model_diff.items():
  60                     weights[v_name] = weights[v_name] + v_value
  61         elif dxo.data_kind == DataKind.WEIGHTS:
  62             weights = dxo.data
  63             if not weights:
  64                 self.log_info(fl_ctx, "No model weights found. Model will not be updated.")
  65             else:
  66                 base_model[ModelLearnableKey.WEIGHTS] = weights
  67 
  68         base_model[ModelLearnableKey.META] = dxo.get_meta_props()
  69         return base_model
  70
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py b/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py
  --- a/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py
  +++ b/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py
  @@ -21,21 +21,21 @@
   
   
   class FullModelShareableGenerator(ShareableGenerator):
  -    def learnable_to_shareable(self, ml: ModelLearnable, fl_ctx: FLContext) -> Shareable:
  -        """Convert Learnable to Shareable.
  +    def learnable_to_shareable(self, model_learnable: ModelLearnable, fl_ctx: FLContext) -> Shareable:
  +        """Convert ModelLearnable to Shareable.
   
           Args:
  -            model (Learnable): model to be converted
  +            model_learnable (ModelLearnable): model to be converted
               fl_ctx (FLContext): FL context
   
           Returns:
  -            Shareable: a shareable containing a DXO object,
  +            Shareable: a shareable containing a DXO object.
           """
  -        dxo = model_learnable_to_dxo(ml)
  +        dxo = model_learnable_to_dxo(model_learnable)
           return dxo.to_shareable()
   
       def shareable_to_learnable(self, shareable: Shareable, fl_ctx: FLContext) -> ModelLearnable:
  -        """Convert Shareable to Learnable.
  +        """Convert Shareable to ModelLearnable.
   
           Supporting TYPE == TYPE_WEIGHT_DIFF or TYPE_WEIGHTS
   
  @@ -43,8 +43,16 @@
               shareable (Shareable): Shareable that contains a DXO object
               fl_ctx (FLContext): FL context
   
  -        Returns: a ModelLearnable object
  +        Returns:
  +            A ModelLearnable object
  +
  +        Raises:
  +            TypeError: if shareable is not of type shareable
  +            ValueError: if data_kind is not `DataKind.WEIGHTS` and is not `DataKind.WEIGHT_DIFF`
           """
  +        if not isinstance(shareable, Shareable):
  +            raise TypeError("shareable must be Shareable, but got {}.".format(type(shareable)))
  +
           base_model = fl_ctx.get_prop(AppConstants.GLOBAL_MODEL)
           if not base_model:
               self.system_panic(reason="No global base model!", fl_ctx=fl_ctx)
  @@ -64,6 +72,10 @@
                   self.log_info(fl_ctx, "No model weights found. Model will not be updated.")
               else:
                   base_model[ModelLearnableKey.WEIGHTS] = weights
  +        else:
  +            raise ValueError(
  +                "data_kind should be either DataKind.WEIGHTS or DataKind.WEIGHT_DIFF, but got {}".format(dxo.data_kind)
  +            )
   
           base_model[ModelLearnableKey.META] = dxo.get_meta_props()
           return base_model
  
verification_info: {"golden_diff": "diff --git a/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py b/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py\n--- a/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py\n+++ b/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py\n@@ -21,21 +21,21 @@\n \n \n class FullModelShareableGenerator(ShareableGenerator):\n-    def learnable_to_shareable(self, ml: ModelLearnable, fl_ctx: FLContext) -> Shareable:\n-        \"\"\"Convert Learnable to Shareable.\n+    def learnable_to_shareable(self, model_learnable: ModelLearnable, fl_ctx: FLContext) -> Shareable:\n+        \"\"\"Convert ModelLearnable to Shareable.\n \n         Args:\n-            model (Learnable): model to be converted\n+            model_learnable (ModelLearnable): model to be converted\n             fl_ctx (FLContext): FL context\n \n         Returns:\n-            Shareable: a shareable containing a DXO object,\n+            Shareable: a shareable containing a DXO object.\n         \"\"\"\n-        dxo = model_learnable_to_dxo(ml)\n+        dxo = model_learnable_to_dxo(model_learnable)\n         return dxo.to_shareable()\n \n     def shareable_to_learnable(self, shareable: Shareable, fl_ctx: FLContext) -> ModelLearnable:\n-        \"\"\"Convert Shareable to Learnable.\n+        \"\"\"Convert Shareable to ModelLearnable.\n \n         Supporting TYPE == TYPE_WEIGHT_DIFF or TYPE_WEIGHTS\n \n@@ -43,8 +43,16 @@\n             shareable (Shareable): Shareable that contains a DXO object\n             fl_ctx (FLContext): FL context\n \n-        Returns: a ModelLearnable object\n+        Returns:\n+            A ModelLearnable object\n+\n+        Raises:\n+            TypeError: if shareable is not of type shareable\n+            ValueError: if data_kind is not `DataKind.WEIGHTS` and is not `DataKind.WEIGHT_DIFF`\n         \"\"\"\n+        if not isinstance(shareable, Shareable):\n+            raise TypeError(\"shareable must be Shareable, but got {}.\".format(type(shareable)))\n+\n         base_model = fl_ctx.get_prop(AppConstants.GLOBAL_MODEL)\n         if not base_model:\n             self.system_panic(reason=\"No global base model!\", fl_ctx=fl_ctx)\n@@ -64,6 +72,10 @@\n                 self.log_info(fl_ctx, \"No model weights found. Model will not be updated.\")\n             else:\n                 base_model[ModelLearnableKey.WEIGHTS] = weights\n+        else:\n+            raise ValueError(\n+                \"data_kind should be either DataKind.WEIGHTS or DataKind.WEIGHT_DIFF, but got {}\".format(dxo.data_kind)\n+            )\n \n         base_model[ModelLearnableKey.META] = dxo.get_meta_props()\n         return base_model\n", "issue": "if/elif statement without else clause in `FullModelShareableGenerator`\nIt would be helpful to add an else statement with a warning message that this DataKind is not supported. I ran into this issue when sending a DataKind.COLLECTION with the shareable by mistake.\r\n\r\nSee https://github.com/NVIDIA/NVFlare/blob/b3ff7844a9bef746218527ccd07601feb66fd94c/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py#L61\r\n\r\nIn the same class, when sending a DXO instead of Shareable type, I got this error\r\n\r\n```\r\nTraceback (most recent call last):\r\n  File \"/home/hroth/Code/nvflare/hroth-agglib/nvflare/app_common/workflows/scatter_and_gather.py\", line 202, in control_flow\r\n    self._global_weights = self.shareable_gen.shareable_to_learnable(aggr_result, fl_ctx)\r\n  File \"/home/hroth/Code/nvflare/hroth-agglib/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py\", line 54, in shareable_to_learnable\r\n    dxo = from_shareable(shareable)\r\n  File \"/home/hroth/Code/nvflare/hroth-agglib/nvflare/apis/dxo.py\", line 120, in from_shareable\r\n    content_type = s.get_header(ReservedHeaderKey.CONTENT_TYPE)\r\nAttributeError: 'DXO' object has no attribute 'get_header'\r\n```\r\nThere should be an instance check here https://github.com/NVIDIA/NVFlare/blob/b3ff7844a9bef746218527ccd07601feb66fd94c/nvflare/app_common/shareablegenerators/full_model_shareable_generator.py#L54\r\n\r\n\r\n\n", "before_files": [{"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\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 nvflare.apis.dxo import DataKind, from_shareable\nfrom nvflare.apis.fl_context import FLContext\nfrom nvflare.apis.shareable import Shareable\nfrom nvflare.app_common.abstract.model import ModelLearnable, ModelLearnableKey, model_learnable_to_dxo\nfrom nvflare.app_common.abstract.shareable_generator import ShareableGenerator\nfrom nvflare.app_common.app_constant import AppConstants\n\n\nclass FullModelShareableGenerator(ShareableGenerator):\n    def learnable_to_shareable(self, ml: ModelLearnable, fl_ctx: FLContext) -> Shareable:\n        \"\"\"Convert Learnable to Shareable.\n\n        Args:\n            model (Learnable): model to be converted\n            fl_ctx (FLContext): FL context\n\n        Returns:\n            Shareable: a shareable containing a DXO object,\n        \"\"\"\n        dxo = model_learnable_to_dxo(ml)\n        return dxo.to_shareable()\n\n    def shareable_to_learnable(self, shareable: Shareable, fl_ctx: FLContext) -> ModelLearnable:\n        \"\"\"Convert Shareable to Learnable.\n\n        Supporting TYPE == TYPE_WEIGHT_DIFF or TYPE_WEIGHTS\n\n        Args:\n            shareable (Shareable): Shareable that contains a DXO object\n            fl_ctx (FLContext): FL context\n\n        Returns: a ModelLearnable object\n        \"\"\"\n        base_model = fl_ctx.get_prop(AppConstants.GLOBAL_MODEL)\n        if not base_model:\n            self.system_panic(reason=\"No global base model!\", fl_ctx=fl_ctx)\n            return base_model\n\n        weights = base_model[ModelLearnableKey.WEIGHTS]\n        dxo = from_shareable(shareable)\n\n        if dxo.data_kind == DataKind.WEIGHT_DIFF:\n            if dxo.data is not None:\n                model_diff = dxo.data\n                for v_name, v_value in model_diff.items():\n                    weights[v_name] = weights[v_name] + v_value\n        elif dxo.data_kind == DataKind.WEIGHTS:\n            weights = dxo.data\n            if not weights:\n                self.log_info(fl_ctx, \"No model weights found. Model will not be updated.\")\n            else:\n                base_model[ModelLearnableKey.WEIGHTS] = weights\n\n        base_model[ModelLearnableKey.META] = dxo.get_meta_props()\n        return base_model\n", "path": "nvflare/app_common/shareablegenerators/full_model_shareable_generator.py"}], "after_files": [{"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\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 nvflare.apis.dxo import DataKind, from_shareable\nfrom nvflare.apis.fl_context import FLContext\nfrom nvflare.apis.shareable import Shareable\nfrom nvflare.app_common.abstract.model import ModelLearnable, ModelLearnableKey, model_learnable_to_dxo\nfrom nvflare.app_common.abstract.shareable_generator import ShareableGenerator\nfrom nvflare.app_common.app_constant import AppConstants\n\n\nclass FullModelShareableGenerator(ShareableGenerator):\n    def learnable_to_shareable(self, model_learnable: ModelLearnable, fl_ctx: FLContext) -> Shareable:\n        \"\"\"Convert ModelLearnable to Shareable.\n\n        Args:\n            model_learnable (ModelLearnable): model to be converted\n            fl_ctx (FLContext): FL context\n\n        Returns:\n            Shareable: a shareable containing a DXO object.\n        \"\"\"\n        dxo = model_learnable_to_dxo(model_learnable)\n        return dxo.to_shareable()\n\n    def shareable_to_learnable(self, shareable: Shareable, fl_ctx: FLContext) -> ModelLearnable:\n        \"\"\"Convert Shareable to ModelLearnable.\n\n        Supporting TYPE == TYPE_WEIGHT_DIFF or TYPE_WEIGHTS\n\n        Args:\n            shareable (Shareable): Shareable that contains a DXO object\n            fl_ctx (FLContext): FL context\n\n        Returns:\n            A ModelLearnable object\n\n        Raises:\n            TypeError: if shareable is not of type shareable\n            ValueError: if data_kind is not `DataKind.WEIGHTS` and is not `DataKind.WEIGHT_DIFF`\n        \"\"\"\n        if not isinstance(shareable, Shareable):\n            raise TypeError(\"shareable must be Shareable, but got {}.\".format(type(shareable)))\n\n        base_model = fl_ctx.get_prop(AppConstants.GLOBAL_MODEL)\n        if not base_model:\n            self.system_panic(reason=\"No global base model!\", fl_ctx=fl_ctx)\n            return base_model\n\n        weights = base_model[ModelLearnableKey.WEIGHTS]\n        dxo = from_shareable(shareable)\n\n        if dxo.data_kind == DataKind.WEIGHT_DIFF:\n            if dxo.data is not None:\n                model_diff = dxo.data\n                for v_name, v_value in model_diff.items():\n                    weights[v_name] = weights[v_name] + v_value\n        elif dxo.data_kind == DataKind.WEIGHTS:\n            weights = dxo.data\n            if not weights:\n                self.log_info(fl_ctx, \"No model weights found. Model will not be updated.\")\n            else:\n                base_model[ModelLearnableKey.WEIGHTS] = weights\n        else:\n            raise ValueError(\n                \"data_kind should be either DataKind.WEIGHTS or DataKind.WEIGHT_DIFF, but got {}\".format(dxo.data_kind)\n            )\n\n        base_model[ModelLearnableKey.META] = dxo.get_meta_props()\n        return base_model\n", "path": "nvflare/app_common/shareablegenerators/full_model_shareable_generator.py"}]}