text: user16619: So I have been trying to get into visualizing proteins in python, so after some research I ended up on a tutorial that was teaching you how to visualize a protein from the COVID-19 virus, so I went and setup anaconda, got jupyter notebook working in vscode, and downloaded the necessary files from the PDB database, and made sure they were in the same directory as my notebook but when I run the the nglview.show_biopython(structure) function I get ValueError: I/O opertation on a closed file. I'm stymied this is my first time using jupyter notebook so maybe there is something I'm missing, I don't know.
  This what the code looks like
  from Bio.PDB import * 
  import nglview as nv
  
  
  parser = PDBParser()
  structure = parser.get_structure("6YYT", "6YYT.pdb")
  view = nv.show_biopython(structure)
  
  The error looks like this
  Output exceeds the size limit. Open the full output data in a text editor
  ---------------------------------------------------------------------------
  ValueError                                Traceback (most recent call last)
  ~\AppData\Local\Temp\ipykernel_8776\2743687014.py in <module>
  ----> 1 view = nv.show_biopython(structure)
  
  c:\Users\jerem\anaconda3\lib\site-packages\nglview\show.py in show_biopython(entity, **kwargs)
      450     '''
      451     entity = BiopythonStructure(entity)
  --> 452     return NGLWidget(entity, **kwargs)
      453 
      454 
  
  c:\Users\jerem\anaconda3\lib\site-packages\nglview\widget.py in __init__(self, structure, representations, parameters, **kwargs)
      243         else:
      244             if structure is not None:
  --> 245                 self.add_structure(structure, **kwargs)
      246 
      247         if representations:
  
  c:\Users\jerem\anaconda3\lib\site-packages\nglview\widget.py in add_structure(self, structure, **kwargs)
     1111         if not isinstance(structure, Structure):
     1112             raise ValueError(f'{structure} is not an instance of Structure')
  -> 1113         self._load_data(structure, **kwargs)
     1114         self._ngl_component_ids.append(structure.id)
     1115         if self.n_components > 1:
  ...
  --> 200         return io_str.getvalue()
      201 
      202 
  
  ValueError: I/O operation on closed file
  
  I only get this error when using nglview.show_biopython, when I run the get_structure() function it appears to read the file just fine. I can visualize other molucles just fine, or maybe that's because I was using the ASE library instead of a file. I don't know, that's why I'm here.
  Update: Recently I found out that I can visualize the protein using nglview.show_file() instead of using nglview.show_biopython(). Even though I can visualize proteins now and technically my problem has been solved I would still like to know why the show_biopython() function isn't working properly.
  
  user10049: tried to understand git, I ended up with this, seems more coherent with the previous habits in the biopython project, but cant push it.
  
  Anyone could pass it along ? [of course needs to be checked out, my tests are OK, but I am a novice].
  
  user10049: I had a similar problem with:
  from Bio.PDB import * 
  import nglview as nv
  
  
  parser = PDBParser(QUIET = True)
  structure = parser.get_structure("2ms2", "2ms2.pdb")
  
  save_pdb = PDBIO()
  save_pdb.set_structure(structure)
  save_pdb.save('pdb_out.pdb')
  
  view = nv.show_biopython(structure)
  view
  
  error was like in question:
  .................site-packages/nglview/adaptor.py:201, in BiopythonStructure.get_structure_string(self)
      199 io_str = StringIO()
      200 io_pdb.save(io_str)
  --> 201 return io_str.getvalue()
  
  ValueError: I/O operation on closed file
  
  I modified site-packages/nglview/adaptor.py:201, in  BiopythonStructure.get_structure_string(self):
  def get_structure_string(self):
          from Bio.PDB import PDBIO
          from io import StringIO
          io_pdb = PDBIO()
          io_pdb.set_structure(self._entity)
          io_str = StringIO()
          io_pdb.save(io_str)
          return io_str.getvalue()
  
  
  with :
  def get_structure_string(self):
          from Bio.PDB import PDBIO
          
          import mmap
          
          io_pdb = PDBIO()
          
          io_pdb.set_structure(self._entity)
          
          mo = mmap_str()
          
          io_pdb.save(mo)
          
          return mo.read()
  
  
  and added this new class mmap_str() , in same file:
  import mmap
  import copy
  
  class mmap_str():
  
      import mmap #added import at top
      
      instance = None
  
      def __init__(self):
      
          self.mm = mmap.mmap(-1, 2)
          
          self.a = ''
          
          b = '\n'
          
          self.mm.write(b.encode(encoding = 'utf-8'))
          
          self.mm.seek(0)
          
          #print('self.mm.read().decode() ',self.mm.read().decode(encoding = 'utf-8'))
          
          self.mm.seek(0)
          
      def __new__(cls, *args, **kwargs):
          if not isinstance(cls.instance, cls):
              cls.instance = object.__new__(cls)
          return cls.instance
          
      def write(self, string):
          
          self.a = str(copy.deepcopy(self.mm.read().decode(encoding = 'utf-8'))).lstrip('\n')
          
          self.mm.seek(0)
          
          #print('a -> ', self.a)
          
          len_a = len(self.a)
          
          self.mm = mmap.mmap(-1, len(self.a)+len(string))
          
          #print('a :', self.a)
          
          #print('len self.mm ', len(self.mm))
          
          #print('lenght string : ', len(string))
          
          #print(bytes((self.a+string).encode()))
          
          self.mm.write(bytes((self.a+string).encode()))
          
          self.mm.seek(0)
          
          #print('written once ')
          
          #self.mm.seek(0)
          
      def read(self):
      
          self.mm.seek(0)
          
          a = self.mm.read().decode().lstrip('\n')
          
          self.mm.seek(0)
          
          return a
          
      def __enter__(self):
          
          return self
   
      def __exit__(self, *args):
          
          pass
  
  
  if I uncomment the print statements I'll get the :
  IOPub data rate exceeded.
  The notebook server will temporarily stop sending output
  to the client in order to avoid crashing it. 
  
  error , but commenting them out I get:
  
  while using thenglview.show_file(filename) I get:
  
  tha's because, as could be seen looking at the pdb_out.pdb file
  outputted by my code, Biopytho.PDB.PDBParser.get_structure(name , filename) doesnt retrieve the pdb header responsible for generate full CRYSTALLOGRAPHIC SYMMETRY/or biopython can't handle it (not sure about this, help if you know better),  but just the coordinates.
  Still don't understand what is going on with the :
  --> 201 return io_str.getvalue()
  
  ValueError: I/O operation on closed file
  
  it could be something related to jupiter ipykernal ? hope somebody could shed more light into this, dont know how the framework runs, but is definitely different from a normal python interpreter. As an example:
  
  Same code in one of my Python virtualenv, will run forever, so it could be ipykernel dont like StringIO()s or do something strange to them ?
  OK thanks to the hint in the answer below, I went inspecting PDBIO.py in github repo for version Biopython 1.80 and compared the save method of PDBIO : def save(self, file, select=_select, write_end=True, preserve_atom_numbering=False): with the one in Biopython 1.79,
  see first bit:
  
  and last bit:
  
  so apparently the big difference is the with fhandle: block in version 1.80.
  So I realized that changing adaptor.py with adding a subclass of StringIO that looks like:
  from io import StringIO
  class StringIO(StringIO):
  
      def __exit__(self, *args, **kwargs):
          
          print('exiting from subclassed StringIO !!!!!')
          
          pass
  
  and modifying def get_structure_string(self): like this:
  def get_structure_string(self):
          from Bio.PDB import PDBIO
          #from io import StringIO
          io_pdb = PDBIO()
          io_pdb.set_structure(self._entity)
          io_str = StringIO()
          io_pdb.save(io_str)
          return io_str.getvalue()
  
  
  
  was enough to get my Biopython 1.80 work in jupiter with nglview.
  That told I am not sure what are the pitfalls of not closing the StringIO object we use for the visualization, but apparently its what Biopython 1.79 was doing like my first answer using a mmap object was doing too (not closing the mmap_str)
  
  user4622: This is an issue with Biopython 1.80, in particular introduced by a commit that automatically closes IO objects sent to PDBIO.save.
  I made a PR to change the behaviour which fixes this issue and should hopefully be in the next Biopython release. Until then, avoiding using Biopython 1.80 should work.
  Thanks @jeremiah-wade and @pippo1980 for digging into this.
  
  user16619: I also figured out another way to fix this problem. After going back to the tutorial I was talking about I saw that it was made back in 2021. After seeing this I wonder if we were using the same verions of each package, turns out we were not. I'm not sure what version of nglview they were using, but they were using biopython 1.79 which was the latest verion back in 2021 and I was using biopython 1.80. While using biopython 1.80 I was getting the error seen above. But now that I'm using biopython 1.79 I get this
  
  So I guess there is something going on with biopython 1.80, so I'm going to stick with 1.79
  
original_text: 16619: <p>So I have been trying to get into visualizing proteins in python, so after some research I ended up on a tutorial that was teaching you how to visualize a protein from the COVID-19 virus, so I went and setup anaconda, got jupyter notebook working in vscode, and downloaded the necessary files from the PDB database, and made sure they were in the same directory as my notebook but when I run the the <code>nglview.show_biopython(structure)</code> function I get <code>ValueError: I/O opertation on a closed file</code>. I'm stymied this is my first time using jupyter notebook so maybe there is something I'm missing, I don't know.</p>
  <p>This what the code looks like</p>
  <pre class="lang-py prettyprint-override"><code>from Bio.PDB import * 
  import nglview as nv
  
  
  parser = PDBParser()
  structure = parser.get_structure(&quot;6YYT&quot;, &quot;6YYT.pdb&quot;)
  view = nv.show_biopython(structure)
  </code></pre>
  <p>The error looks like this</p>
  <pre><code>Output exceeds the size limit. Open the full output data in a text editor
  ---------------------------------------------------------------------------
  ValueError                                Traceback (most recent call last)
  ~\AppData\Local\Temp\ipykernel_8776\2743687014.py in &lt;module&gt;
  ----&gt; 1 view = nv.show_biopython(structure)
  
  c:\Users\jerem\anaconda3\lib\site-packages\nglview\show.py in show_biopython(entity, **kwargs)
      450     '''
      451     entity = BiopythonStructure(entity)
  --&gt; 452     return NGLWidget(entity, **kwargs)
      453 
      454 
  
  c:\Users\jerem\anaconda3\lib\site-packages\nglview\widget.py in __init__(self, structure, representations, parameters, **kwargs)
      243         else:
      244             if structure is not None:
  --&gt; 245                 self.add_structure(structure, **kwargs)
      246 
      247         if representations:
  
  c:\Users\jerem\anaconda3\lib\site-packages\nglview\widget.py in add_structure(self, structure, **kwargs)
     1111         if not isinstance(structure, Structure):
     1112             raise ValueError(f'{structure} is not an instance of Structure')
  -&gt; 1113         self._load_data(structure, **kwargs)
     1114         self._ngl_component_ids.append(structure.id)
     1115         if self.n_components &gt; 1:
  ...
  --&gt; 200         return io_str.getvalue()
      201 
      202 
  
  ValueError: I/O operation on closed file
  </code></pre>
  <p>I only get this error when using <code>nglview.show_biopython</code>, when I run the <code>get_structure()</code> function it appears to read the file just fine. I can visualize other molucles just fine, or maybe that's because I was using the ASE library instead of a file. I don't know, that's why I'm here.</p>
  <p>Update: Recently I found out that I can visualize the protein using <code>nglview.show_file()</code> instead of using <code>nglview.show_biopython()</code>. Even though I can visualize proteins now and technically my problem has been solved I would still like to know why the <code>show_biopython()</code> function isn't working properly.</p>
   10049: <p>tried to understand git, I ended up with this, seems more coherent with the previous habits in the biopython project, but cant push it.</p>
  <p><a href="https://i.stack.imgur.com/zGqfC.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/zGqfC.png" alt="enter image description here" /></a></p>
  <p>Anyone could pass it along ? [of course needs to be checked out, my tests are OK, but I am a novice].</p>
   10049: <p>I had a similar problem with:</p>
  <pre><code>from Bio.PDB import * 
  import nglview as nv
  
  
  parser = PDBParser(QUIET = True)
  structure = parser.get_structure(&quot;2ms2&quot;, &quot;2ms2.pdb&quot;)
  
  save_pdb = PDBIO()
  save_pdb.set_structure(structure)
  save_pdb.save('pdb_out.pdb')
  
  view = nv.show_biopython(structure)
  view
  </code></pre>
  <p>error was like in question:</p>
  <pre><code>.................site-packages/nglview/adaptor.py:201, in BiopythonStructure.get_structure_string(self)
      199 io_str = StringIO()
      200 io_pdb.save(io_str)
  --&gt; 201 return io_str.getvalue()
  
  ValueError: I/O operation on closed file
  </code></pre>
  <p>I modified <code>site-packages/nglview/adaptor.py:201, in  BiopythonStructure.get_structure_string(self)</code>:</p>
  <pre><code>def get_structure_string(self):
          from Bio.PDB import PDBIO
          from io import StringIO
          io_pdb = PDBIO()
          io_pdb.set_structure(self._entity)
          io_str = StringIO()
          io_pdb.save(io_str)
          return io_str.getvalue()
  
  </code></pre>
  <p>with :</p>
  <pre><code>def get_structure_string(self):
          from Bio.PDB import PDBIO
          
          import mmap
          
          io_pdb = PDBIO()
          
          io_pdb.set_structure(self._entity)
          
          mo = mmap_str()
          
          io_pdb.save(mo)
          
          return mo.read()
  
  </code></pre>
  <p>and added this new class <code>mmap_str()</code> , in same file:</p>
  <pre><code>import mmap
  import copy
  
  class mmap_str():
  
      import mmap #added import at top
      
      instance = None
  
      def __init__(self):
      
          self.mm = mmap.mmap(-1, 2)
          
          self.a = ''
          
          b = '\n'
          
          self.mm.write(b.encode(encoding = 'utf-8'))
          
          self.mm.seek(0)
          
          #print('self.mm.read().decode() ',self.mm.read().decode(encoding = 'utf-8'))
          
          self.mm.seek(0)
          
      def __new__(cls, *args, **kwargs):
          if not isinstance(cls.instance, cls):
              cls.instance = object.__new__(cls)
          return cls.instance
          
      def write(self, string):
          
          self.a = str(copy.deepcopy(self.mm.read().decode(encoding = 'utf-8'))).lstrip('\n')
          
          self.mm.seek(0)
          
          #print('a -&gt; ', self.a)
          
          len_a = len(self.a)
          
          self.mm = mmap.mmap(-1, len(self.a)+len(string))
          
          #print('a :', self.a)
          
          #print('len self.mm ', len(self.mm))
          
          #print('lenght string : ', len(string))
          
          #print(bytes((self.a+string).encode()))
          
          self.mm.write(bytes((self.a+string).encode()))
          
          self.mm.seek(0)
          
          #print('written once ')
          
          #self.mm.seek(0)
          
      def read(self):
      
          self.mm.seek(0)
          
          a = self.mm.read().decode().lstrip('\n')
          
          self.mm.seek(0)
          
          return a
          
      def __enter__(self):
          
          return self
   
      def __exit__(self, *args):
          
          pass
  
  </code></pre>
  <p>if I uncomment the print statements I'll get the :</p>
  <pre><code>IOPub data rate exceeded.
  The notebook server will temporarily stop sending output
  to the client in order to avoid crashing it. 
  </code></pre>
  <p>error , but commenting them out I get:</p>
  <p><a href="https://i.stack.imgur.com/siSKY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/siSKY.png" alt="" /></a></p>
  <p>while using the<code>nglview.show_file(filename)</code> I get:</p>
  <p><a href="https://i.stack.imgur.com/olG6j.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/olG6j.png" alt="enter image description here" /></a></p>
  <p>tha's because, as could be seen looking at the <code>pdb_out.pdb</code> file</p>
  <p>outputted by my code, <code>Biopytho.PDB.PDBParser.get_structure(name , filename)</code> doesnt retrieve the pdb header responsible for generate full CRYSTALLOGRAPHIC SYMMETRY/or biopython can't handle it (not sure about this, help if you know better),  but just the coordinates.</p>
  <p>Still don't understand what is going on with the :</p>
  <pre><code>--&gt; 201 return io_str.getvalue()
  
  ValueError: I/O operation on closed file
  </code></pre>
  <p>it could be something related to jupiter ipykernal ? hope somebody could shed more light into this, dont know how the framework runs, but is definitely different from a normal python interpreter. As an example:</p>
  <p><a href="https://i.stack.imgur.com/cXRlL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/cXRlL.png" alt="enter image description here" /></a></p>
  <p>Same code in one of my Python virtualenv, will run forever, so it could be ipykernel dont like <code>StringIO()</code>s or do something strange to them ?</p>
  <p>OK thanks to the hint in the answer below, I went inspecting PDBIO.py in github repo for version Biopython 1.80 and compared the save method of PDBIO : <a href="https://github.com/biopython/biopython/blob/5ffdce852ba3721ca945ec383a69382507b4fa1b/Bio/PDB/PDBIO.py#L299" rel="nofollow noreferrer">def save(self, file, select=_select, write_end=True, preserve_atom_numbering=False):</a> with the one in Biopython 1.79,</p>
  <p>see first bit:
  <a href="https://i.stack.imgur.com/PCtMW.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/PCtMW.png" alt="enter image description here" /></a></p>
  <p>and last bit:
  <a href="https://i.stack.imgur.com/1hjO5.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1hjO5.png" alt="enter image description here" /></a></p>
  <p>so apparently the big difference is the <code>with fhandle:</code> block in version 1.80.</p>
  <p>So I realized that changing <code>adaptor.py</code> with adding a subclass of <code>StringIO</code> that looks like:</p>
  <pre><code>from io import StringIO
  class StringIO(StringIO):
  
      def __exit__(self, *args, **kwargs):
          
          print('exiting from subclassed StringIO !!!!!')
          
          pass
  </code></pre>
  <p>and modifying <code>def get_structure_string(self):</code> like this:</p>
  <pre><code>def get_structure_string(self):
          from Bio.PDB import PDBIO
          #from io import StringIO
          io_pdb = PDBIO()
          io_pdb.set_structure(self._entity)
          io_str = StringIO()
          io_pdb.save(io_str)
          return io_str.getvalue()
  
  
  </code></pre>
  <p>was enough to get my Biopython 1.80 work in jupiter with nglview.</p>
  <p>That told I am not sure what are the pitfalls of not closing the StringIO object we use for the visualization, but apparently its what Biopython 1.79 was doing like my first answer using a mmap object was doing too (not closing the mmap_str)</p>
   4622: <p>This is an issue with Biopython 1.80, in particular introduced by <a href="https://github.com/biopython/biopython/commit/be77131200821bb01254c87fb14ee1bf6c81dd4b" rel="nofollow noreferrer">a commit</a> that automatically closes IO objects sent to <code>PDBIO.save</code>.</p>
  <p>I made <a href="https://github.com/biopython/biopython/pull/4200" rel="nofollow noreferrer">a PR</a> to change the behaviour which fixes this issue and should hopefully be in the next Biopython release. Until then, avoiding using Biopython 1.80 should work.</p>
  <p>Thanks @jeremiah-wade and @pippo1980 for digging into this.</p>
   16619: <p>I also figured out another way to fix this problem. After going back to the tutorial I was talking about I saw that it was made back in 2021. After seeing this I wonder if we were using the same verions of each package, turns out we were not. I'm not sure what version of nglview they were using, but they were using biopython 1.79 which was the latest verion back in 2021 and I was using biopython 1.80. While using biopython 1.80 I was getting the error seen above. But now that I'm using biopython 1.79 I get this
  <a href="https://i.stack.imgur.com/iRzUG.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/iRzUG.png" alt="enter image description here" /></a></p>
  <p>So I guess there is something going on with biopython 1.80, so I'm going to stick with 1.79</p>
  