Repository: wandb/wandb
Pull request: [WB-8897] Properly handle command line args with service
Fixes WB-8897
Fixes #3370 

Description
-----------
What does the PR do?
When command line arguments are resolved we save them as list in `Settings`, but when we convert the `Settings` to protobuf message to send over the socket we only converted tuples, meaning all list types of `Settings` will be `None`. To avoid this we fix the utility function in `service_base` to convert lists. As well as convert the command line arguments to tuples (we don't need this change since we already addressing list with the fix to the utility function - consider to remove)

Testing
-------
How was this PR tested?

Checklist
-------
- Name PR "[WB-NNNN][WB-MMMM] Add support for..." similar to entries in CHANGELOG.md
- Include reference to internal ticket "Fixes WB-NNNN" (and github issue "Fixes #NNNN" if applicable)


Problem statement:
[CLI]: args for "Command" are not saved with the run when using `wandb.require("service")`
### Describe the bug

When `wandb.require("service")` is used and a new wandb experiment is created, the command line arguments of the python script are not saved at all - not in the local files/logs and not in the server.  

To reproduce:
```python 
import sys
import wandb
sys.argv=["script.py", "--arg1", "--arg2"]
wandb.require("service")
wandb.init()
```
The web UI will show `Command` `script.py`  

---
Expected behavior can be seen with the following code:
```python 
import sys
import wandb
sys.argv=["script.py", "--arg1", "--arg2"]
wandb.init()
```
The web UI will show `Command` `script.py --arg1 --arg2`  

### Environment

WandB version: 0.12.11

OS: Ubuntu 20.04

Python version: 3.9.7

Hints from issue discussion:

Commit message: cast _args to tuple

Patch to review:
diff --git a/wandb/sdk/service/service_base.py b/wandb/sdk/service/service_base.py
index 82002f2a275..a7ccf00ae03 100644
--- a/wandb/sdk/service/service_base.py
+++ b/wandb/sdk/service/service_base.py
@@ -39,7 +39,7 @@ def _pbmap_apply_dict(
             sv.float_value = v
         elif isinstance(v, str):
             sv.string_value = v
-        elif isinstance(v, tuple):
+        elif isinstance(v, (tuple, list)):
             sv.tuple_value.string_values.extend(v)
         m[k].CopyFrom(sv)
 
diff --git a/wandb/sdk/wandb_settings.py b/wandb/sdk/wandb_settings.py
index 7f72a8d3131..cb8f51e8043 100644
--- a/wandb/sdk/wandb_settings.py
+++ b/wandb/sdk/wandb_settings.py
@@ -1289,7 +1289,7 @@ def _infer_settings_from_environment(
         if os.path.exists("/usr/local/cuda/version.txt"):
             with open("/usr/local/cuda/version.txt") as f:
                 settings["_cuda"] = f.read().split(" ")[-1].strip()
-        settings["_args"] = sys.argv[1:]
+        settings["_args"] = tuple(sys.argv[1:])
         settings["_os"] = platform.platform(aliased=True)
         settings["_python"] = platform.python_version()
         # hack to make sure we don't hang on windows


Code review comments:
diff_hunk: @@ -39,7 +39,7 @@ def _pbmap_apply_dict(
             sv.float_value = v
         elif isinstance(v, str):
             sv.string_value = v
-        elif isinstance(v, tuple):
+        elif isinstance(v, (tuple, list)):
path: wandb/sdk/service/service_base.py
text: @user1:
maybe?
```suggestion
        elif hasattr(v, "__iter__") and not isinstance(v, (str, bytes)):
```