title: PyContextProtocol example for pyo3?
body: <p>In the <code>__enter__</code> method I want to return an object which is accessible in Rust and Python, so that Rust is able to update values in the object and Python can read the updated values.</p>
  
  <p>I would like to have something like this:</p>
  
  <pre><code>#![feature(specialization)]
  
  use std::thread;
  
  use pyo3::prelude::*;
  use pyo3::types::{PyType, PyAny, PyDict};
  use pyo3::exceptions::ValueError;
  use pyo3::PyContextProtocol;
  use pyo3::wrap_pyfunction;
  
  #[pyclass]
  #[derive(Debug, Clone)]
  pub struct Statistics {
      pub files: u32,
      pub errors: Vec&lt;String&gt;,
  }
  
  fn counter(
      root_path: &amp;str,
      statistics: &amp;mut Statistics,
  ) {
      statistics.files += 1;
      statistics.errors.push(String::from("Foo"));
  }
  
  #[pyfunction]
  pub fn count(
      py: Python,
      root_path: &amp;str,
  ) -&gt; PyResult&lt;PyObject&gt; {
      let mut statistics = Statistics { 
          files: 0,
          errors: Vec::new(),
      };
  
      let rc: std::result::Result&lt;(), std::io::Error&gt; = py.allow_threads(|| {
          counter(root_path, &amp;mut statistics);
          Ok(())
      });
      let pyresult = PyDict::new(py);
      match rc {
          Err(e) =&gt; { pyresult.set_item("error", e.to_string()).unwrap();
                      return Ok(pyresult.into())
                    },
          _ =&gt; ()
      }
      pyresult.set_item("files", statistics.files).unwrap();
      pyresult.set_item("errors", statistics.errors).unwrap();
      Ok(pyresult.into())
  }
  
  #[pyclass]
  #[derive(Debug)]
  pub struct Count {
      root_path: String,
      exit_called: bool,
      thr: Option&lt;thread::JoinHandle&lt;()&gt;&gt;,
      statistics: Statistics,
  }
  
  #[pymethods]
  impl Count {
      #[new]
      fn __new__(
          obj: &amp;PyRawObject,
          root_path: &amp;str,
      ) {
          obj.init(Count {
              root_path: String::from(root_path),
              exit_called: false,
              thr: None,
              statistics: Statistics { 
                  files: 0,
                  errors: Vec::new(),
              },
          });
      }
  
      #[getter]
      fn statistics(&amp;self) -&gt; PyResult&lt;Statistics&gt; {
         Ok(Statistics { files: self.statistics.files,
                         errors: self.statistics.errors.to_vec(), })
      }
  }
  
  #[pyproto]
  impl&lt;'p&gt; PyContextProtocol&lt;'p&gt; for Count {
      fn __enter__(&amp;mut self) -&gt; PyResult&lt;Py&lt;Count&gt;&gt; {
          let gil = GILGuard::acquire();
          self.thr = Some(thread::spawn(|| {
              counter(self.root_path.as_ref(), &amp;mut self.statistics)
          }));
          Ok(PyRefMut::new(gil.python(), *self).unwrap().into())
      }
  
      fn __exit__(
          &amp;mut self,
          ty: Option&lt;&amp;'p PyType&gt;,
          _value: Option&lt;&amp;'p PyAny&gt;,
          _traceback: Option&lt;&amp;'p PyAny&gt;,
      ) -&gt; PyResult&lt;bool&gt; {
          self.thr.unwrap().join();
          let gil = GILGuard::acquire();
          self.exit_called = true;
          if ty == Some(gil.python().get_type::&lt;ValueError&gt;()) {
              Ok(true)
          } else {
              Ok(false)
          }
      }
  }
  
  #[pymodule(count)]
  fn init(_py: Python, m: &amp;PyModule) -&gt; PyResult&lt;()&gt; {
      m.add_class::&lt;Count&gt;()?;
      m.add_wrapped(wrap_pyfunction!(count))?;
      Ok(())
  }
  </code></pre>
  
  <p>But I'm getting the following error:</p>
  
  <pre><code>error[E0477]: the type `[closure@src/lib.rs:90:39: 92:10 self:&amp;mut &amp;'p mut Count]` does not fulfill the required lifetime
    --&gt; src/lib.rs:90:25
     |
  90 |         self.thr = Some(thread::spawn(|| {
     |                         ^^^^^^^^^^^^^
     |
     = note: type must satisfy the static lifetime
  </code></pre>