error: unpack requires a string argument of length 8
Question: I was running my script and I stumbled upon on this error

    
    
    WARNING *** file size (24627) not 512 + multiple of sector size (512)
    WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
    
    Traceback (most recent call last):
        File "C:\Email Attachments\whatever.py", line 20, in <module>
            main()
    File "C:\Email Attachments\whatever.py", line 17, in main
        csv_from_excel()
    File "C:\Email Attachments\whatever.py", line 7, in csv_from_excel
        sh = wb.sheet_by_name('B2B_REP_YLD_100_D_SQ.rpt')
    File "C:\Python27\lib\site-packages\xlrd\book.py", line 442, in sheet_by_name
        return self.sheet_by_index(sheetx)
    File "C:\Python27\lib\site-packages\xlrd\book.py", line 432, in sheet_by_index
        return self._sheet_list[sheetx] or self.get_sheet(sheetx)
    File "C:\Python27\lib\site-packages\xlrd\book.py", line 696, in get_sheet
        sh.read(self)
    File "C:\Python27\lib\site-packages\xlrd\sheet.py", line 1055, in read
        dim_tuple = local_unpack('<ixxH', data[4:12])
    error: unpack requires a string argument of length 8
    

I was trying to process this excel file.
<https://drive.google.com/file/d/0B12NevhOGQGRMkRVdExuYjFveDQ/edit?usp=sharing>

One solution that I found is that I have to open manually the spreadsheet,
save it, then close it before I run my script of converting .xls to .csv. I
find this solution a bit cumbersome and clunky.

This kind of spreadsheet is saved daily in my drive via an Outlook Macro.
Unprocessed data is increasing that's why I turned into scripting to ease the
job.


Answer: Who made the Outlook macro that's dumping this file? `xlrd` uses byte level
unpacking to read in the Excel file, and is failing to read a field in this
excel file. There are ways to follow where its failing, but none to
automatically recover from this type of error.

The erroneous data seems to be at `data[4:12]` of a specific frame (we'll see
later), which should be a bytestring that's parsed as such:

  1. one integer (i)
  2. 2 pad bytes (xx)
  3. unsigned short 2 byte integer (H).

You can set xlrd to `DEBUG mode`, which will show you which bytes its parsing,
and exactly where in the file there is an error:

    
    
    import xlrd
    xlrd.DEBUG = 2
    workbook = xlrd.open_workbook(u'/home/sparker/Downloads/20131117_040934_B2B_REP_YLD_100_D_LT.xls')
    

Here's the results, slightly trimmed down for the sake of SO:

    
    
    parse_globals: record code is 0x0293
    parse_globals: record code is 0x0293
    parse_globals: record code is 0x0085
    CODEPAGE: codepage 1200 -> encoding 'utf_16_le'
    BOUNDSHEET: bv=80 data '\xfd\x04\x00\x00\x00\x00\x18\x00B2B_REP_YLD_100_D_SQ.rpt'
    BOUNDSHEET: inx=0 vis=0 sheet_name=u'B2B_REP_YLD_100_D_SQ.rpt' abs_posn=1277 sheet_type=0x00
    parse_globals: record code is 0x000a
    GET_SHEETS: [u'B2B_REP_YLD_100_D_SQ.rpt'] [1277]
    GET_SHEETS: sheetno = 0 [u'B2B_REP_YLD_100_D_SQ.rpt'] [1277]
    reqd: 0x0010
    
    getbof(): data='\x00\x06\x10\x00\xbb\r\xcc\x07\x00\x00\x00\x00\x06\x00\x00\x00'
    getbof(): op=0x0809 version2=0x0600 streamtype=0x0010
    getbof(): BOF found at offset 1277; savpos=1277
    BOF: op=0x0809 vers=0x0600 stream=0x0010 buildid=3515 buildyr=1996 -> BIFF80
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "build/bdist.macosx-10.4-x86_64/egg/xlrd/__init__.py", line 457, in open_workbook
    
      File "build/bdist.macosx-10.4-x86_64/egg/xlrd/__init__.py", line 1007, in get_sheets
    
      File "build/bdist.macosx-10.4-x86_64/egg/xlrd/__init__.py", line 998, in get_sheet
    
      File "build/bdist.macosx-10.4-x86_64/egg/xlrd/sheet.py", line 864, in read
    struct.error: unpack requires a string argument of length 8
    

Specifically, you can see that it parses the name of the workbook named
`u'B2B_REP_YLD_100_D_SQ.rpt`.

Lets check the source code. The traceback throws an error
[here](https://github.com/python-excel/xlrd/blob/master/xlrd/sheet.py#L1058)
where we can see from [the parent loop](https://github.com/python-
excel/xlrd/blob/master/xlrd/sheet.py#L1048) that we're trying to parse the
`XL_DIMENSION` and `XL_DIMENSION2` values. These directly correspond to the
shape of the Excel Sheet.

And that's where there's a problem in your workbook. It's not being made
correctly. So, back to my original question, who made the excel macro? It
needs to be fixed. But that's for another SO question, some other time.

