Repository: piskvorky/gensim

Issue:
LdaModel.save does not allow setting `ignore` to a custom value
In `LdaModel.save` the `ignore` list is explicitly passed to the parent method, making it impossible to add anything to that list. I propose that the `ignore` list be handled in the following way instead.

```
if 'ignore' in kwargs:
    kwargs['ignore'] = list(set(['state', 'dispatcher']) | set(kwargs['ignore']))
else:
    kwargs['ignore'] = ['state', 'dispatcher']
super(LdaModel, self).save(fname, *args, **kwargs)
```



Discussion:
That makes sense, thanks! Can you open a pull request?


Resolving patch:
diff --git a/gensim/models/ldamodel.py b/gensim/models/ldamodel.py
--- a/gensim/models/ldamodel.py
+++ b/gensim/models/ldamodel.py
@@ -41,6 +41,7 @@
 from scipy.special import gammaln, psi  # gamma function utils
 from scipy.special import polygamma
 from six.moves import xrange
+import six
 
 # log(sum(exp(x))) that tries to avoid overflow
 try:
@@ -829,11 +830,19 @@ def __getitem__(self, bow, eps=None):
         """
         return self.get_document_topics(bow, eps)
 
-    def save(self, fname, *args, **kwargs):
+    def save(self, fname, ignore=['state', 'dispatcher'], *args, **kwargs):
         """
         Save the model to file.
 
         Large internal arrays may be stored into separate files, with `fname` as prefix.
+        
+        `separately` can be used to define which arrays should be stored in separate files.
+        
+        `ignore` parameter can be used to define which variables should be ignored, i.e. left
+        out from the pickled lda model. By default the internal `state` is ignored as it uses
+        its own serialisation not the one provided by `LdaModel`. The `state` and `dispatcher
+        will be added to any ignore parameter defined.
+
 
         Note: do not save as a compressed file if you intend to load the file back with `mmap`.
 
@@ -850,7 +859,17 @@ def save(self, fname, *args, **kwargs):
         """
         if self.state is not None:
             self.state.save(utils.smart_extension(fname, '.state'), *args, **kwargs)
-        super(LdaModel, self).save(fname, *args, ignore=['state', 'dispatcher'], **kwargs)
+        
+        # make sure 'state' and 'dispatcher' are ignored from the pickled object, even if
+        # someone sets the ignore list themselves
+        if ignore is not None and ignore:
+            if isinstance(ignore, six.string_types):
+                ignore = [ignore]
+            ignore = [e for e in ignore if e] # make sure None and '' are not in the list
+            ignore = list(set(['state', 'dispatcher']) | set(ignore))
+        else:
+            ignore = ['state', 'dispatcher']
+        super(LdaModel, self).save(fname, *args, ignore=ignore, **kwargs)
 
     @classmethod
     def load(cls, fname, *args, **kwargs):


Test patch:
diff --git a/gensim/test/test_models.py b/gensim/test/test_models.py
--- a/gensim/test/test_models.py
+++ b/gensim/test/test_models.py
@@ -322,6 +322,17 @@ def testPersistence(self):
         tstvec = []
         self.assertTrue(numpy.allclose(model[tstvec], model2[tstvec])) # try projecting an empty vector
 
+    def testPersistenceIgnore(self):
+        fname = testfile()
+        model = ldamodel.LdaModel(self.corpus, num_topics=2)
+        model.save(fname, ignore='id2word')
+        model2 = ldamodel.LdaModel.load(fname)
+        self.assertTrue(model2.id2word is None)
+        
+        model.save(fname, ignore=['id2word'])
+        model2 = ldamodel.LdaModel.load(fname)
+        self.assertTrue(model2.id2word is None)
+    
     def testPersistenceCompressed(self):
         fname = testfile() + '.gz'
         model = self.class_(self.corpus, num_topics=2)