Repository: simonsobs/ocs

Issue:
MatchedClient(instance_id) causes argparse to run on sys.argv
If you do something simple like
```
  c = MatchedClient('acu1')
```
then sys.argv will get run through the site_config parser.  This causes trouble when you want to use MatchedClient in anything where sys.argv is non-trivial, such as in jupyter or a script with its own command line args.  The work-around is to pass args=[] to this constructor.  But it would be better if by default there was no inspection of sys.argv.

The MatchedClient code should be changed as follows:  If args=None is passed in to the constructor, that should result in args=[] being passed through to site_config.  (If a user really wants to pass sys.argv through, they can do that explicitly in MatchedClient instantiation.)

Comments:

Patch:
diff --git a/ocs/matched_client.py b/ocs/matched_client.py
index b5be3a6..5a32114 100644
--- a/ocs/matched_client.py
+++ b/ocs/matched_client.py
@@ -79,19 +79,22 @@ class MatchedClient:
     """
 
     def __init__(self, instance_id, **kwargs):
-        """MatchedClient __init__ function.
-
+        """
         Args:
             instance_id (str): Instance id for agent to run
             args (list or args object, optional):
                 Takes in the parser arguments for the client.
-                If None, reads from command line.
+                If None, pass an empty list.
                 If list, reads in list elements as arguments.
                 Defaults to None.
 
-        For additional kwargs see site_config.get_control_client.
+        .. note::
+            For additional ``**kwargs`` see site_config.get_control_client.
 
         """
+        if kwargs.get('args') is None:
+            kwargs['args'] = []
+
         self._client = site_config.get_control_client(instance_id, **kwargs)
         self.instance_id = instance_id
 


Test patch:
diff --git a/tests/test_matched_client.py b/tests/test_matched_client.py
new file mode 100644
index 0000000..1e8765d
--- /dev/null
+++ b/tests/test_matched_client.py
@@ -0,0 +1,28 @@
+import os
+from unittest.mock import MagicMock, patch
+from ocs.matched_client import MatchedClient
+
+mocked_client = MagicMock()
+mock_from_yaml = MagicMock()
+
+
+@patch('ocs.client_http.ControlClient', mocked_client)
+@patch('ocs.site_config.SiteConfig.from_yaml', mock_from_yaml)
+@patch('sys.argv', ['example_client.py', 'test'])
+def test_extra_argv():
+    """If there are extra arguments in sys.argv and args=[] is not set when
+    instantiating a MatchedClient, then internally
+    site_config.get_control_client() will inspect sys.argv[1:], which causes
+    issues down the line when run through the site_config parser.
+
+    Here we patch in a mocked ControlClient to avoid needing to talk to a
+    crossbar server. We also patch in a mocked from_yaml() method, to avoid
+    needing to read a real site file. Lastly, and most importantly, we patch in
+    sys.argv with an actual additional argument. This will cause an
+    "unrecognized arguments" error when argparse inspects sys.argv within the
+    site_config parser.
+
+    """
+    # Set for get_config to pick up on
+    os.environ["OCS_CONFIG_DIR"] = '/tmp/'
+    MatchedClient("test")