Search code examples
pythonioerror

<type 'exceptions.IOError'> [Errno 9] Bad file descriptor


The code below is a part of a program which is aimed to capture data from Bloomberg terminal and dump it into SQLite database. It worked pretty well on my 32-bit windows XP. But it keeps giving me "get_history.histfetch error: [Errno 9] Bad file descriptor" on 64-bit windows 7, although there shouldn't be a problem using 32-bit python under 64-bit OS. Sometimes this problem can be solved by simply exit the program and open it again, but sometimes it just won't work. Right now I'm really confused about what leads to this problem. I looked at the source code and found the problem is generated while calling "histfetch" and I have NO idea which part of the code is failing. Can anyone help me out here...? I really really appreciate it. Thanks in advance.

def run(self):
    try: pythoncom.CoInitializeEx(pythoncom.COINIT_APARTMENTTHREADED)
    except: pass
    while 1:
        if self.trigger:
            try: self.histfetch()
            except Exception,e:
                logging.error('get_history.histfetch error: %s %s' % (str(type(e)),str(e)))
                if self.errornotify != None:
                    self.errornotify('get_history error','%s %s' % ( str(type(e)), str(e) ) )
            self.trigger = 0
        if self.telomere: break
        time.sleep(0.5)

def histfetch(self):
    blpcon = win32com.client.gencache.EnsureDispatch('blpapicom.Session')
    blpcon.Start()
    dbcon = sqlite3.connect(self.dbfile)
    c = dbcon.cursor()
    fieldcodes = {}
    symcodes = {}
    trysleep(c,'select fid,field from fields')
    for fid,field in c.fetchall():
        # these are different types so this will be ok
        fieldcodes[fid] = field
        fieldcodes[field] = fid
    trysleep(c,'select sid,symbol from symbols')
    for sid,symbol in c.fetchall():
        symcodes[sid] = symbol
        symcodes[symbol] = sid
    for instr in self.instructions:
        if instr[1] != 'minute': continue
        sym,rollspec = instr[0],instr[2]
        print 'MINUTE',sym
        limits = []
        sid = getsid(sym,symcodes,dbcon,c)
        trysleep(c,'select min(epoch),max(epoch) from minute where sid=?',(sid,))
        try: mine,maxe = c.fetchone()
        except: mine,maxe = None,None
        print sym,'minute data limits',mine,maxe
        rr = getreqrange(mine,maxe)
        if rr == None: continue
        start,end = rr
        dstart = start.strftime('%Y%m%d')
        dend = end.strftime('%Y%m%d')
        try: # if rollspec is 'noroll', then this will fail and goto except-block
            ndaysbefore = int(rollspec)
            print 'hist fetch for %s, %i days' % (sym,ndaysbefore)
            rolldb.update_roll_db(blpcon,(sym,))
            names = rolldb.get_contract_range(sym,ndaysbefore)
        except: names = {sym:None}
        # sort alphabetically here so oldest always gets done first
        #  (at least within the decade)
        sorted_contracts = names.keys()
        sorted_contracts.sort()
        for contract in sorted_contracts:
            print 'partial fetch',contract,names[contract]
            if names[contract] == None:
                _start,_end = start,end
            else:
                da,db = names[contract]
                dc,dd = start,end
                try: _start,_end = get_overlap(da,db,dc,dd)
                except: continue # because get_overlap returning None cannot assign to tuple
            # localstart and end are for printing and logging
            localstart = _start.strftime('%Y/%m/%d %H:%M')
            localend = _end.strftime('%Y/%m/%d %H:%M')
            _start = datetime.utcfromtimestamp(time.mktime(_start.timetuple())).strftime(self.blpfmt)
            _end = datetime.utcfromtimestamp(time.mktime(_end.timetuple())).strftime(self.blpfmt)
            logging.debug('requesting intraday bars for %s (%s): %s to %s' % (sym,contract,localstart,localend))
            print 'start,end:',localstart,localend
            result = get_minute(blpcon,contract,_start,_end)
            if len(result) == 0:
                logging.error('warning: 0-length minute data fetch for %s,%s,%s' % (contract,_start,_end))
                continue
            event_count = len(result.values()[0])
            print event_count,'events returned'
            lap = time.clock()
            # todo: split up writes: no more than 5000 before commit (so other threads get a chance)
            #   100,000 rows is 13 seconds on my machine. 5000 should be 0.5 seconds.
            try:
                for i in range(event_count):
                    epoch = calendar.timegm(datetime.strptime(str(result['time'][i]),'%m/%d/%y %H:%M:%S').timetuple())
                    # this uses sid (from sym), NOT contract
                    row = (sid,epoch,result['open'][i],result['high'][i],result['low'][i],result['close'][i],result['volume'][i],result['numEvents'][i])
                    trysleep(c,'insert or ignore into minute (sid,epoch,open,high,low,close,volume,nevents) values (?,?,?,?,?,?,?,?)',row)
                dbcon.commit()
            except Exception,e:
                print 'ERROR',e,'iterating result object'
                logging.error(datetime.now().strftime() + ' error in get_history.histfetch writing DB')
                # todo: tray notify the error and log it
            lap = time.clock() - lap
            print 'database write of %i rows in %.2f seconds' % (event_count,lap)
            logging.debug(' -- minute bars %i rows (%.2f s)' % (event_count,lap))
    for instr in self.instructions:
        oldestdaily = datetime.now().replace(hour=0,minute=0,second=0,microsecond=0) - timedelta(self.dailyback)
        sym = instr[0]
        if instr[1] != 'daily': continue
        print 'DAILY',sym
        fields = instr[2]
        rollspec = instr[3]
        sid = getsid(sym,symcodes,dbcon,c)
        unionrange = None,None
        for f in fields:
            try: fid = fieldcodes[f]
            except:
                trysleep(c,'insert into fields (field) values (?)',(f,))
                trysleep(c,'select fid from fields where field=?',(f,))
                fid, = c.fetchone()
                dbcon.commit()
                fieldcodes[fid] = f
                fieldcodes[f] = fid
            trysleep(c,'select min(epoch),max(epoch) from daily where sid=? and fid=?',(sid,fid))
            mine,maxe = c.fetchone()
            if mine == None or maxe == None:
                unionrange = None
                break
            if unionrange == (None,None):
                unionrange = mine,maxe
            else:
                unionrange = max(mine,unionrange[0]),min(maxe,unionrange[1])
        print sym,'daily unionrange',unionrange
        yesterday = datetime.now().replace(hour=0,minute=0,second=0,microsecond=0) - timedelta(days=1)
        if unionrange == None:
            reqrange = oldestdaily,yesterday
        else:
            mine = datetime.fromordinal(unionrange[0])
            maxe = datetime.fromordinal(unionrange[1])
            print 'comparing',mine,maxe,oldestdaily,yesterday
            if oldestdaily < datetime.fromordinal(unionrange[0]): a = oldestdaily
            else: a = maxe
            reqrange = a,yesterday
        if reqrange[0] >= reqrange[1]:
            print 'skipping daily',sym,'because we\'re up to date'
            continue
        print 'daily request range',sym,reqrange,reqrange[0] > reqrange[1]
        try:
            ndaysbefore = int(rollspec) # exception if it's 'noroll'
            print 'hist fetch for %s, %i days' % (sym,ndaysbefore)
            rolldb.update_roll_db(blpcon,(sym,))
            names = rolldb.get_contract_range(sym,ndaysbefore,daily=True)
        except: names = {sym:None}
        # sort alphabetically here so oldest always gets done first
        #  (at least within the year)
        sorted_contracts = names.keys()
        sorted_contracts.sort()
        start,end = reqrange
        for contract in sorted_contracts:
            print 'partial fetch',contract,names[contract]
            if names[contract] == None:
                _start,_end = start,end
            else:
                da,db = names[contract]
                dc,dd = start,end
                try: _start,_end = get_overlap(da,db,dc,dd)
                except: continue # because get_overlap returning None cannot assign to tuple
            _start = _start.strftime('%Y%m%d')
            _end = _end.strftime('%Y%m%d')
            logging.info('daily bars for %s (%s), %s - %s' % (sym,contract,_start,_end))
            result = get_daily(blpcon,(contract,),fields,_start,_end)
            try: result = result[contract]
            except:
                print 'result doesn\'t contain requested symbol'
                logging.error("ERROR: symbol '%s' not in daily request result" % contract)
                # todo: log and alert error
                continue
            if not 'date' in result:
                print 'result has no date field'
                logging.error('ERROR: daily result has no date field')
                # todo: log and alert error
                continue
            keys = result.keys()
            keys.remove('date')
            logging.info(' -- %i days returned' % len(result['date']))
            for i in range(len(result['date'])):
                ordinal = datetime.fromtimestamp(int(result['date'][i])).toordinal()
                for k in keys:
                    trysleep(c,'insert or ignore into daily (sid,fid,epoch,value) values (?,?,?,?)',(sid,fieldcodes[k],ordinal,result[k][i]))
            dbcon.commit()

Solution

  • Print the full traceback instead of just the exception message. The traceback will show you where the exception was raised and hence what the problem is:

    import traceback
    
    ...
    
        try: self.histfetch()
        except Exception,e:
            logging.error('get_history.histfetch error: %s %s' % (str(type(e)),str(e)))
            logging.error(traceback.format_exc())
            if self.errornotify != None:
                self.errornotify('get_history error','%s %s' % ( str(type(e)), str(e) ) )
    

    Update:

    With the above (or similar, the idea being to look at the full traceback), you say:

    it said it's with the "print" functions. The program works well after I disable all the "print" functions.

    The print function calls you have in your post uses syntax valid in python 2.x only. If that is what you are using, perhaps the application that runs your script has undefined print and you're supposed to use a log function, otherwise I can't see anything wrong with the calls (unless you mean only one of the prints was the issue, then I would need to see the exact error to identify -- post this if you want to figure this out). If you are using Python 3.x, then you must use print(a, b, c, ...), see 3.x docs.