Repository: biolab/orange3

Issue:
Pickle file from SC Datasets not loaded correctly
##### Orange version
<!-- From menu _Help→About→Version_ or code `Orange.version.full_version` -->
3.21.dev

##### Expected behavior

AML-1k.pickle should load correctly. 

##### Actual behavior

AML-1k.pickle, Stimulated and resting immune cells (stimulated), ... cannot be loaded since there was a change in `variable.py` script - line 730 - one argument was removed. It seems that the pickle file will need to be generated again. Or is there any other option to fix it @JakaKokosar, @janezd?

##### Steps to reproduce the behavior

Open SC datasets widget and load `Bone marrow mononuclear cells with AML (sample)` dataset.


##### Additional info (worksheets, data, screenshots, ...)

```
Traceback (most recent call last):
  File "/Users/primoz/Documents/orange3/Orange/widgets/data/owdatasets.py", line 211, in <lambda>
    self.view.doubleClicked.connect(lambda: self.unconditional_commit())
  File "/Users/primoz/Documents/orange3/Orange/widgets/data/owdatasets.py", line 482, in commit
    self.commit_cached(di.file_path)
  File "/Users/primoz/Documents/orange3/Orange/widgets/data/owdatasets.py", line 519, in commit_cached
    self.Outputs.data.send(self.load_data(path))
  File "/Users/primoz/Desktop/repositories/orange3-single-cell/orangecontrib/single_cell/widgets/owscdatasets.py", line 39, in load_data
    data = Orange.data.Table(path)
  File "/Users/primoz/Documents/orange3/Orange/data/table.py", line 224, in __new__
    return cls.from_file(args[0])
  File "/Users/primoz/Documents/orange3/Orange/data/table.py", line 619, in from_file
    data = reader.read()
  File "/Users/primoz/Documents/orange3/Orange/data/io.py", line 949, in read
    table = pickle.load(f)
  File "/Users/primoz/Documents/orange3/Orange/data/variable.py", line 33, in make_variable
    var = cls.make(*args)
TypeError: make() takes from 2 to 4 positional arguments but 5 were given
```




Discussion:
It would be better to add a backward compatibility check.

Function `make_variable`, which fails, is used solely for unpickling. The length of `*args` before line 33 should be 5. If it's 6, we should remove the last element, which corresponds to the (now removed) `base_value`.

Resolving patch:
diff --git a/Orange/data/variable.py b/Orange/data/variable.py
--- a/Orange/data/variable.py
+++ b/Orange/data/variable.py
@@ -29,7 +29,13 @@ def make_variable(cls, compute_value, *args):
     if compute_value is not None:
         return cls(*args, compute_value=compute_value)
     if issubclass(cls, DiscreteVariable):
-        name, values = args[:2]
+        values = args[1]
+
+        # backward compatibility - `base_value` argument was removed in the
+        # `make` function - with this fix it is removed if exist
+        # ars should have len = 3, if more remove last element
+        args = args[:3]
+
         var = cls.make(*args)
         # The `var.values` are in general a superset of `values` with different
         # order. Only use it if it is a structural subtype of the requested
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -206,7 +206,8 @@ def configuration(parent_package='', top_path=None):
     "Orange.widgets.unsupervised": ["icons/*.svg"],
     "Orange.widgets.utils": ["_webview/*.js"],
     "Orange.tests": ["xlsx_files/*.xlsx", "datasets/*.tab",
-                     "datasets/*.basket", "datasets/*.csv"]
+                     "datasets/*.basket", "datasets/*.csv",
+                     "datasets/*.pkl", "datasets/*.pkl.gz"]
 }
 
 


Test patch:
diff --git a/Orange/tests/datasets/sailing-orange-3-20.pkl b/Orange/tests/datasets/sailing-orange-3-20.pkl
new file mode 100644
Binary files /dev/null and b/Orange/tests/datasets/sailing-orange-3-20.pkl differ
diff --git a/Orange/tests/datasets/sailing-orange-3-20.pkl.gz b/Orange/tests/datasets/sailing-orange-3-20.pkl.gz
new file mode 100644
Binary files /dev/null and b/Orange/tests/datasets/sailing-orange-3-20.pkl.gz differ
diff --git a/Orange/tests/datasets/sailing-orange-3-21.pkl b/Orange/tests/datasets/sailing-orange-3-21.pkl
new file mode 100644
Binary files /dev/null and b/Orange/tests/datasets/sailing-orange-3-21.pkl differ
diff --git a/Orange/tests/datasets/sailing-orange-3-21.pkl.gz b/Orange/tests/datasets/sailing-orange-3-21.pkl.gz
new file mode 100644
Binary files /dev/null and b/Orange/tests/datasets/sailing-orange-3-21.pkl.gz differ
diff --git a/Orange/tests/test_io.py b/Orange/tests/test_io.py
--- a/Orange/tests/test_io.py
+++ b/Orange/tests/test_io.py
@@ -8,9 +8,12 @@
 import shutil
 import io
 
+from Orange import data
+
 from Orange.data.io import FileFormat, TabReader, CSVReader, PickleReader
 from Orange.data.table import get_sample_datasets_dir
-from Orange.data import Table
+from Orange.data import Table, Variable
+from Orange.tests import test_dirname
 
 
 class WildcardReader(FileFormat):
@@ -94,6 +97,14 @@ def test_locate_wildcard_extension(self):
 
 class TestReader(unittest.TestCase):
 
+    def setUp(self):
+        Variable._clear_all_caches()
+        data.table.dataset_dirs.append(test_dirname())
+        print(data.table.dataset_dirs)
+
+    def tearDown(self):
+        data.table.dataset_dirs.remove(test_dirname())
+
     def test_open_bad_pickle(self):
         """
         Raise TypeError when PickleReader reads a pickle
@@ -144,3 +155,31 @@ def test_header_call(self, writer):
         writer.reset_mock()
         CSVReader.write_headers(writer, Table("iris"), True)
         self.assertEqual(len(writer.call_args_list), 3)
+
+    def test_load_pickle(self):
+        """
+        This function tests whether pickled files in older Orange loads
+        correctly with newer version of Orange.
+        """
+        # load pickles created with Orange 3.20
+        # in next version there is a change in variables.py - line 738
+        # which broke back compatibility - tests were introduced after the fix
+        print(data.table.dataset_dirs)
+        data1 = Table("datasets/sailing-orange-3-20.pkl")
+        data2 = Table("datasets/sailing-orange-3-20.pkl.gz")
+
+        # load pickles created with Orange 3.21
+        data3 = Table("datasets/sailing-orange-3-21.pkl")
+        data4 = Table("datasets/sailing-orange-3-21.pkl.gz")
+
+        examples_count = 20
+        self.assertEqual(examples_count, len(data1))
+        self.assertEqual(examples_count, len(data2))
+        self.assertEqual(examples_count, len(data3))
+        self.assertEqual(examples_count, len(data4))
+
+        attributes_count = 3
+        self.assertEqual(attributes_count, len(data1.domain.attributes))
+        self.assertEqual(attributes_count, len(data2.domain.attributes))
+        self.assertEqual(attributes_count, len(data3.domain.attributes))
+        self.assertEqual(attributes_count, len(data4.domain.attributes))