Repository: arviz-devs/arviz

Issue:
Check for InferenceData input on from_pymc3
`pymc3.sample` has a keyword argument that makes the function return an InferenceData object, `from_pymc3` is called under the hood by pymc3. This can generate confusion when doing also posterior predictive checks or similar postprocessing, and it is common to end up calling `from_pymc3` manually again but using the `InferenceData` as `trace` argument, which does not work nor should it work.

We should check for InferenceData input on io_pymc3 to make sure the input is not an inferencedata and if it is raise an error pointing people out to https://arviz-devs.github.io/arviz/api/generated/arviz.InferenceData.extend.html#arviz.InferenceData.extend.



Discussion:
Hi @OriolAbril I'd like to work on this... can you assign this to me?
Hey @OriolAbril , sorry for the delay, I got stuck somewhere else.

Anyways, even though you described it perfectly I just wanted to make sure that I need to enable type checking for `io_pymc3`'s input and if in case it's of type `InferenceData`, it should raise the error as you mentioned... Am I missing anything here? 
That is all. 

Resolving patch:
diff --git a/arviz/data/io_pymc3.py b/arviz/data/io_pymc3.py
--- a/arviz/data/io_pymc3.py
+++ b/arviz/data/io_pymc3.py
@@ -104,6 +104,12 @@ def __init__(
         # way to access the model from the trace.
         self.attrs = None
         if trace is not None:
+            if isinstance(self.trace, InferenceData):
+                raise ValueError(
+                    "Using the `InferenceData` as a `trace` argument won't work. "
+                    "Please use the `arviz.InferenceData.extend` method to extend the "
+                    "`InferenceData` with groups from another `InferenceData`."
+                )
             if self.model is None:
                 self.model = list(self.trace._straces.values())[  # pylint: disable=protected-access
                     0


Test patch:
diff --git a/arviz/tests/external_tests/test_data_pymc.py b/arviz/tests/external_tests/test_data_pymc.py
--- a/arviz/tests/external_tests/test_data_pymc.py
+++ b/arviz/tests/external_tests/test_data_pymc.py
@@ -10,6 +10,7 @@
 
 from arviz import (  # pylint: disable=wrong-import-position
     InferenceData,
+    from_dict,
     from_pymc3,
     from_pymc3_predictions,
 )
@@ -107,7 +108,7 @@ def test_from_pymc(self, data, eight_schools_params, chains, draws):
                 )
 
     def test_from_pymc_predictions(self, data, eight_schools_params):
-        "Test that we can add predictions to a previously-existing InferenceData."
+        """Test that we can add predictions to a previously-existing InferenceData."""
         test_dict = {
             "posterior": ["mu", "tau", "eta", "theta"],
             "sample_stats": ["diverging", "lp"],
@@ -139,6 +140,15 @@ def test_from_pymc_predictions(self, data, eight_schools_params):
             assert ivalues.shape[0] == 1  # one chain in predictions
             assert np.all(np.isclose(ivalues[0], values))
 
+    def test_from_pymc_trace_inference_data(self):
+        """Check if the error is raised successfully after passing InferenceData as trace"""
+        idata = from_dict(
+            posterior={"A": np.random.randn(2, 10, 2), "B": np.random.randn(2, 10, 5, 2)}
+        )
+        assert isinstance(idata, InferenceData)
+        with pytest.raises(ValueError):
+            from_pymc3(trace=idata, model=pm.Model())
+
     def test_from_pymc_predictions_new(self, data, eight_schools_params):
         # check creating new
         inference_data, posterior_predictive = self.make_predictions_inference_data(