diff options
| author | Damian Johnson <atagar@torproject.org> | 2018-08-04 17:04:24 -0700 |
|---|---|---|
| committer | Damian Johnson <atagar@torproject.org> | 2018-08-04 17:14:00 -0700 |
| commit | 8ec17d804e7f6142fae0f14120bdf06e523e3982 (patch) | |
| tree | d0d68ed3b59154b7f07472a4a4b10be87bdfc444 | |
| parent | d42e9e1953ab5eac3677e16c51c1a4c28ef965ec (diff) | |
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.
| -rw-r--r-- | stem/descriptor/__init__.py | 17 |
1 files changed, 17 insertions, 0 deletions
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 |
