[tor-commits] [stem/master] Better error message if file objects aren't seekable

atagar at torproject.org atagar at torproject.org
Sun Aug 5 00:44:30 UTC 2018


commit 8ec17d804e7f6142fae0f14120bdf06e523e3982
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Aug 4 17:04:24 2018 -0700

    Better error message if file objects aren't seekable
    
    As reported by teor, stem.descriptor's parse_file() function cannot accept
    stdin...
    
      https://trac.torproject.org/projects/tor/ticket/23859
    
    The trouble is that not all file objects in python are seekable. I'd *like*
    to handle address this transparently by buffering the content...
    
      try:
        descriptor_file.tell()
      except IOError:
        # file's not seekable, wrapping in a buffer that is
    
        descriptor_file = io.BytesIO(descriptor_file.read())
    
    This works great if our stream has content...
    
      % cat my_descriptors | python demo.py
    
    *But* hangs indefinitely if no EOF is present in the stream.
    
      % python demo.py   <= hangs
    
    Turns out non-blocking, platform independent reading of streams like stdin is
    pretty tricky...
    
      http://eyalarubas.com/python-subproc-nonblock.html
    
    As such simply providing callers with a more descriptive exception. If they
    know their stream won't block *they* can add the above wrapper to provide
    us with a seekable file object.
---
 stem/descriptor/__init__.py | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index 05255648..a9860140 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -93,6 +93,13 @@ __all__ = [
   'Descriptor',
 ]
 
+UNSEEKABLE_MSG = """\
+File object isn't seekable. Try wrapping it with a BytesIO instead...
+
+  content = my_file.read()
+  parsed_descriptors = stem.descriptor.parse_file(io.BytesIO(content))
+"""
+
 KEYWORD_CHAR = 'a-zA-Z0-9-'
 WHITESPACE = ' \t'
 KEYWORD_LINE = re.compile('^([%s]+)(?:[%s]+(.*))?$' % (KEYWORD_CHAR, WHITESPACE))
@@ -218,6 +225,16 @@ def parse_file(descriptor_file, descriptor_type = None, validate = False, docume
 
     return
 
+  # Not all files are seekable. If unseekable then advising the user.
+  #
+  # Python 3.x adds an io.seekable() method, but not an option with python 2.x
+  # so using an experimental call to tell() to determine this.
+
+  try:
+    descriptor_file.tell()
+  except IOError:
+    raise IOError(UNSEEKABLE_MSG)
+
   # The tor descriptor specifications do not provide a reliable method for
   # identifying a descriptor file's type and version so we need to guess
   # based on its filename. Metrics descriptors, however, can be identified



More information about the tor-commits mailing list