Repository: pandas-dev/pandas

Issue:
ASV: occasional asv failures on xlwt
https://travis-ci.org/pandas-dev/pandas-ci/jobs/343616367
this is on current pandas master (this is just the CI job running it).

excel asv's

```
The following asvs benchmarks (if any) failed.
[ 43.02%] ··· Running io.excel.Excel.time_read_excel                  1/3 failed
                   xlwt      failed 
DONE displaying failed asvs benchmarks.
```

I have seen this work as well. maybe a race-condition?


Discussion:
from ``(pandas) bash-3.2$ more asv_bench/benchmarks/io/excel.py ``
```
def setup(...):
      ....
        self.bio_write = BytesIO()
        self.bio_write.seek(0)
        self.writer_write = ExcelWriter(self.bio_write, engine=engine)

    def time_read_excel(self, engine):
        read_excel(self.bio_read)

    def time_write_excel(self, engine):
        self.df.to_excel(self.writer_write, sheet_name='Sheet1')
        self.writer_write.save()
```

I think the ``time_write_excel`` should have the ``.writer_write`` setup I think.
If it is defined in the setup function (as it is now), it should be available in the benchmark function. It would be strange that this solves it.
its passing 1 our of n times: https://travis-ci.org/pandas-dev/pandas-ci/jobs/345996588
cc @mroeschke @WillAyd if you have any ideas
Perhaps we should be explicitly closing the `BytesIO` objects that are getting created in a `teardown`? Due to the intermittency of it I'm wondering if the GC is taking an pass at closing those for us, but getting tripped up with the parallelized execution that asv provides
Looks to be specifically a problem with the `time_read_excel` benchmark.

```
File "/home/travis/build/pandas-dev/pandas-ci/pandas/asv_bench/benchmarks/io/excel.py", line 29, in time_read_excel
                    read_excel(self.bio_read)
File "/home/travis/miniconda3/envs/pandas/lib/python3.6/site-packages/pandas-0.23.0.dev0+381.g8f1dfa74e-py3.6-linux-x86_64.egg/pandas/util/_decorators.py", line 172, in wrapper
                    return func(*args, **kwargs)
File "/home/travis/miniconda3/envs/pandas/lib/python3.6/site-packages/pandas-0.23.0.dev0+381.g8f1dfa74e-py3.6-linux-x86_64.egg/pandas/util/_decorators.py", line 172, in wrapper
                    return func(*args, **kwargs)
File "/home/travis/miniconda3/envs/pandas/lib/python3.6/site-packages/pandas-0.23.0.dev0+381.g8f1dfa74e-py3.6-linux-x86_64.egg/pandas/io/excel.py", line 315, in read_excel
                    io = ExcelFile(io, engine=engine)
File "/home/travis/miniconda3/envs/pandas/lib/python3.6/site-packages/pandas-0.23.0.dev0+381.g8f1dfa74e-py3.6-linux-x86_64.egg/pandas/io/excel.py", line 391, in __init__
                    self.book = xlrd.open_workbook(file_contents=data)
File "/home/travis/miniconda3/envs/pandas/lib/python3.6/site-packages/xlrd/__init__.py", line 116, in open_workbook
                    with open(filename, "rb") as f:
                TypeError: expected str, bytes or os.PathLike object, not NoneType
```

Digging into `xlrd.open_workbook` for the `file_contents` variable.
http://www.lexicon.net/sjmachin/xlrd.html#xlrd.open_workbook-function
> file_contents
... as a string or an mmap.mmap object or some other behave-alike object. If file_contents is supplied, filename will not be used, except (possibly) in messages.

Looks like `filename=None` is the default as well, but for some reason its being used despite the note above?

its funny because it has worked at times. really odd. 
While it doesn't explain *why* this is happening I think if we add `io.seek(0)` just before the below line it will "fix" the issue at hand (at least it did locally for me):

https://github.com/pandas-dev/pandas/blob/74dbfd0aa9b44936a4db7969bfe25f526fef53ce/pandas/io/excel.py#L390
can u replicate this in a test? (and then fix)?

Resolving patch:
diff --git a/pandas/io/excel.py b/pandas/io/excel.py
--- a/pandas/io/excel.py
+++ b/pandas/io/excel.py
@@ -387,6 +387,10 @@ def __init__(self, io, **kwds):
             self.book = io
         elif not isinstance(io, xlrd.Book) and hasattr(io, "read"):
             # N.B. xlrd.Book has a read attribute too
+            if hasattr(io, 'seek'):
+                # GH 19779
+                io.seek(0)
+
             data = io.read()
             self.book = xlrd.open_workbook(file_contents=data)
         elif isinstance(self._io, compat.string_types):


Test patch: