Repository: iossifovlab/gpf

Issue:
[BUG] Families from In-Memory genotype storage are without tags
**What happened**:

When loading families from in-memory genotype storage, they have no pedigree tags. This breaks functionality for filtering families by tags in the datasets statistics UI.

**What you expected to happen**:

The pedigree tags should be built when loading families from in-memory genotype storage.

**Minimal Complete Verifiable Example**:

You can use the `helloworld` de Novo example from the getting started guide:
https://www.iossifovlab.com/gpfuserdocs/administration/getting_started.html#example-import-of-de-novo-variants-helloworld

**Environment**:

- GPF version: development version 3.7dev from the master branch


Discussion:

Patch:
diff --git a/dae/dae/impala_storage/schema1/impala_variants.py b/dae/dae/impala_storage/schema1/impala_variants.py
index b15ad6b3d..7b0368f07 100644
--- a/dae/dae/impala_storage/schema1/impala_variants.py
+++ b/dae/dae/impala_storage/schema1/impala_variants.py
@@ -197,6 +197,7 @@ class ImpalaVariants:
         self.ped_df = self._fetch_pedigree()
         self.families = FamiliesData.from_pedigree_df(self.ped_df)
         # Temporary workaround for studies that are imported without tags
+        # e.g. production data that is too large to reimport
         FamiliesLoader._build_families_tags(
             self.families, {"ped_tags": True}
         )
diff --git a/dae/dae/import_tools/import_tools.py b/dae/dae/import_tools/import_tools.py
index 5835110ce..5f78beff1 100644
--- a/dae/dae/import_tools/import_tools.py
+++ b/dae/dae/import_tools/import_tools.py
@@ -122,8 +122,11 @@ class ImportProject():
         """Get params for loading the pedigree."""
         families_filename = self.get_pedigree_filename()
 
-        families_params = self.import_config["input"]["pedigree"]
-        families_params = self._add_loader_prefix(families_params, "ped_")
+        families_params = {}
+        families_params.update(FamiliesLoader.cli_defaults())
+        config_params = self.import_config["input"]["pedigree"]
+        config_params = self._add_loader_prefix(config_params, "ped_")
+        families_params.update(config_params)
 
         return families_filename, families_params
 
diff --git a/dae/dae/variants_loaders/raw/loader.py b/dae/dae/variants_loaders/raw/loader.py
index 37029a947..a051b3c35 100644
--- a/dae/dae/variants_loaders/raw/loader.py
+++ b/dae/dae/variants_loaders/raw/loader.py
@@ -172,8 +172,14 @@ class CLILoader(ABC):
 
     @classmethod
     def cli_defaults(cls):
-        argument_destinations = [arg.destination for arg in cls._arguments()]
-        defaults = [arg.default_value for arg in cls._arguments()]
+        argument_destinations = [
+            arg.destination for arg in cls._arguments()
+            if arg.destination is not None
+        ]
+        defaults = [
+            arg.default_value for arg in cls._arguments()
+            if arg.destination is not None
+        ]
         return dict(zip(argument_destinations, defaults))
 
     @classmethod


Test patch:
diff --git a/dae/dae/import_tools/tests/test_import_project.py b/dae/dae/import_tools/tests/test_import_project.py
index 4980b2bde..ea4521e96 100644
--- a/dae/dae/import_tools/tests/test_import_project.py
+++ b/dae/dae/import_tools/tests/test_import_project.py
@@ -49,3 +49,11 @@ def test_config_filenames_external_input_and_annotation():
     )
     project = ImportProject.build_from_config(import_config)
     assert project.config_filenames == ["annotation.yaml"]
+
+
+def test_tags_on_by_default(resources_dir):
+    config_fn = str(resources_dir / "vcf_import" / "import_config.yaml")
+    project = ImportProject.build_from_file(config_fn)
+    _, params = project.get_pedigree_params()
+    assert "ped_tags" in params
+    assert params["ped_tags"] is True
diff --git a/dae/dae/inmemory_storage/tests/test_inmemory_import_storage.py b/dae/dae/inmemory_storage/tests/test_inmemory_import_storage.py
index 93e883ec8..32c50d24f 100644
--- a/dae/dae/inmemory_storage/tests/test_inmemory_import_storage.py
+++ b/dae/dae/inmemory_storage/tests/test_inmemory_import_storage.py
@@ -16,6 +16,7 @@ def test_simple_project_pedigree_params(simple_project):
     assert params["ped_person"] == "pId"
     assert params["ped_mom"] == "mId"
     assert params["ped_dad"] == "dId"
+    assert params["ped_tags"] is True
 
 
 def test_simple_project_pedigree_size(simple_project):
diff --git a/dae/dae/variants_loaders/raw/tests/test_base_loader.py b/dae/dae/variants_loaders/raw/tests/test_base_loader.py
new file mode 100644
index 000000000..9e5b3e017
--- /dev/null
+++ b/dae/dae/variants_loaders/raw/tests/test_base_loader.py
@@ -0,0 +1,36 @@
+from dae.variants_loaders.raw.loader import CLILoader, CLIArgument
+
+
+class TestLoader(CLILoader):  # pylint: disable=missing-class-docstring
+    @classmethod
+    def _arguments(cls):
+        arguments = []
+        arguments.append(CLIArgument(
+            "positional",
+            value_type=str,
+            metavar="<positional>",
+            help_text="Some positional argument",
+        ))
+        arguments.append(CLIArgument(
+            "--kwarg1",
+            default_value=1,
+            help_text="First kwarg",
+        ))
+        arguments.append(CLIArgument(
+            "--kwarg2",
+            default_value=2,
+            help_text="Second kwarg",
+        ))
+        return arguments
+
+
+def test_cli_defaults_does_not_include_positionals():
+    """
+    Test for a bug where positionals were included in cli_defaults.
+
+    Positional arguments have no destination and were mapped to None
+    in the output.
+    """
+    loader = TestLoader()
+    defaults = loader.cli_defaults()
+    assert set(defaults.keys()) == set(["kwarg1", "kwarg2"])