Repository: lightly-ai/lightly

Issue:
lightly-download fails for integer tag names
lightly-download fails for integer tag names

For the `tag_name` `1000`, the following warning appears:
> Possible bug: I get `warnings.warn(f'The specified tag {tag_name} does not exist`

The source of the problem is probably in this line:
https://github.com/lightly-ai/lightly/blob/db33b15de6f77e50b0c815c4c405a8fb371d22e7/lightly/cli/download_cli.py#L44

Current guess: Either the api sends the string as a number or the command-line tool parses the string as a number which makes the lookup fail.


Discussion:

Resolving patch:
diff --git a/lightly/cli/download_cli.py b/lightly/cli/download_cli.py
--- a/lightly/cli/download_cli.py
+++ b/lightly/cli/download_cli.py
@@ -27,9 +27,10 @@
 
 
 def _download_cli(cfg, is_cli_call=True):
-    tag_name = cfg['tag_name']
-    dataset_id = cfg['dataset_id']
-    token = cfg['token']
+
+    tag_name = str(cfg['tag_name'])
+    dataset_id = str(cfg['dataset_id'])
+    token = str(cfg['token'])
 
     if not tag_name or not token or not dataset_id:
         print_as_warning('Please specify all of the parameters tag_name, token and dataset_id')
@@ -69,7 +70,7 @@ def _download_cli(cfg, is_cli_call=True):
     samples = [api_workflow_client.filenames_on_server[i] for i in chosen_samples_ids]
 
     # store sample names in a .txt file
-    filename = cfg['tag_name'] + '.txt'
+    filename = tag_name + '.txt'
     with open(filename, 'w') as f:
         for item in samples:
             f.write("%s\n" % item)


Test patch:
diff --git a/tests/api_workflow/mocked_api_workflow_client.py b/tests/api_workflow/mocked_api_workflow_client.py
--- a/tests/api_workflow/mocked_api_workflow_client.py
+++ b/tests/api_workflow/mocked_api_workflow_client.py
@@ -151,8 +151,11 @@ def get_tags_by_dataset_id(self, dataset_id, **kwargs):
         tag_4 = TagData(id='sampled_tag_xyz', dataset_id=dataset_id, prev_tag_id="preselected_tag_id_xyz",
                         bit_mask_data="0x3", name='sampled_tag_xyz', tot_size=4,
                         created_at=1577836800, changes=dict())
-        tags = [tag_1, tag_2, tag_3, tag_4]
-        no_tags_to_return = getattr(self, "no_tags", 4)
+        tag_5 = TagData(id='tag_with_integer_name', dataset_id=dataset_id, prev_tag_id=None,
+                        bit_mask_data='0x1', name='1000', tot_size=4,
+                        created_at=1577836800, changes=dict())
+        tags = [tag_1, tag_2, tag_3, tag_4, tag_5]
+        no_tags_to_return = getattr(self, "no_tags", 5)
         tags = tags[:no_tags_to_return]
         return tags
 
diff --git a/tests/cli/test_cli_download.py b/tests/cli/test_cli_download.py
--- a/tests/cli/test_cli_download.py
+++ b/tests/cli/test_cli_download.py
@@ -1,13 +1,14 @@
 import os
-import re
 import sys
 import tempfile
 
+import pytest
 import torchvision
 from hydra.experimental import compose, initialize
 
 import lightly
-from tests.api_workflow.mocked_api_workflow_client import MockedApiWorkflowSetup, MockedApiWorkflowClient
+from tests.api_workflow.mocked_api_workflow_client import MockedApiWorkflowSetup
+from tests.api_workflow.mocked_api_workflow_client import MockedApiWorkflowClient
 
 
 class TestCLIDownload(MockedApiWorkflowSetup):
@@ -36,15 +37,13 @@ def create_fake_dataset(self, n_data: int = 5):
         self.output_dir = tempfile.mkdtemp()
 
     def parse_cli_string(self, cli_words: str):
-        cli_words = cli_words.replace("lightly-download ", "")
-        cli_words = re.split("=| ", cli_words)
-        assert len(cli_words) % 2 == 0
-        dict_keys = cli_words[0::2]
-        dict_values = cli_words[1::2]
-        for key, value in zip(dict_keys, dict_values):
-            value = value.strip('\"')
-            value = value.strip('\'')
-            self.cfg[key] = value
+        cli_words = cli_words.replace('lightly-download ', '')
+        overrides = cli_words.split(' ')
+        with initialize(config_path='../../lightly/cli/config/'):
+            self.cfg = compose(
+                config_name='config',
+                overrides=overrides,
+            )
 
     def test_parse_cli_string(self):
         cli_string = "lightly-download token='123' dataset_id='XYZ'"
@@ -98,6 +97,18 @@ def test_download_copy_from_input_to_output_dir(self):
         self.parse_cli_string(cli_string)
         lightly.cli.download_cli(self.cfg)
 
+    def test_download_from_tag_with_integer_name(self):
+        """Test to reproduce issue #575."""
+        # use tag name "1000"
+        cli_string = "lightly-download token='123' dataset_id='dataset_1_id' tag_name=1000"
+        self.parse_cli_string(cli_string)
+        with pytest.warns(None) as record:
+            lightly.cli.download_cli(self.cfg)
+        # check if the warning "Tag with name 1000 does not exist" is raised
+        # if so, the cli string was not parsed correctly
+        # (i.e. as int instead of str)
+        self.assertEqual(len(record), 0)
+
     def tearDown(self) -> None:
         try:
             os.remove(f"{self.cfg['tag_name']}.txt")