-1

I'm working on my python script using the version 2.6 for XBMC media application.

I have got a problem with my python script, I'm trying to pull the data off from the sqlite3 database but I'm getting an error TypeError: string indices must be integers.

The error are jumping on this line:

programming = channelMap[row['channel']], row["title"], row["start_date"], row["stop_date"]

Here is the full code:

import xbmc
import xbmcgui
import xbmcaddon
import os
import urllib2
import StringIO
import sqlite3
from sqlite3 import dbapi2 as database
from xml.etree import ElementTree
import xml.etree.ElementTree as ET
from UserDict import DictMixin
import datetime
import time

class MyClass(xbmcgui.WindowXML):

    def onAction(self, action):

        #DOWNLOAD THE XML SOURCE HERE
        url = ADDON.getSetting('allchannels.url')
        req = urllib2.Request(url)
        response = urllib2.urlopen(req)
        data = response.read()
        response.close()
        profilePath = xbmc.translatePath(os.path.join('special://userdata/addon_data/script.tvguide', ''))

        if os.path.exists(profilePath):
           profilePath = profilePath + 'source.db'
           con = database.connect(profilePath)
           cur = con.cursor()
           cur.execute('CREATE TABLE programs(channel TEXT, title TEXT, start_date TIMESTAMP, stop_date TIMESTAMP, description TEXT)')
           con.commit()
           con.close
           tv_elem = ElementTree.parse(StringIO.StringIO(data)).getroot()
           profilePath = xbmc.translatePath(os.path.join('special://userdata/addon_data/script.tvguide', ''))
           profilePath = profilePath + 'source.db'
           con = sqlite3.connect(profilePath)
           cur = con.cursor()
           channels = OrderedDict()

           # Get the loaded data
           for channel in tv_elem.findall('channel'):
                channel_name = channel.find('display-name').text
                for program in channel.findall('programme'):
                   title = program.find('title').text
                   start_time = program.get("start")
                   stop_time = program.get("stop")
                   cur.execute("INSERT INTO programs(channel, title, start_date, stop_date)" + " VALUES(?, ?, ?, ?)", [channel_name, title, start_time, stop_time])
                   con.commit()
                   print 'Channels store into database are now successfully!'

                   cur.execute('SELECT channel, title, start_date, stop_date FROM programs')
                   programList = list()
                   channelMap = dict()
                   results = cur.fetchall()
                   cur.close


                   for channel_result in results:
                      for row in channel_result:
                         programming = channelMap[row['channel']], row["title"], row["start_date"], row["stop_date"]
                         print(programming)

I keep getting a same request of error in my XBMC log.

EDIT: When I try this:

programList = list()
channelMap = dict()
for c in channels:
if c.id:
   channelMap[c.id] = c
   strCh = '(\'' + '\',\''.join(channelMap.keys()) + '\')'
   cur.execute('SELECT * FROM programs WHERE channel')
   for row in cur:
      programming = program(channelMap[row['channel']], row["title"], row["start_date"], row["stop_date"])
      programList.append(programming)  
      print(programming)

Here is the error on the xbmc log:

- NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
Error Type: <type 'exceptions.TypeError'>
Error Contents: tuple indices must be integers, not str
Traceback (most recent call last):
File "C:\Users\user\AppData\Roaming\XBMC\addons\script.tvguide\test.py", line 1679, in onAction
programming = program(channelMap[row['channel']], row["title"], row["start_date"], row["stop_date"])
TypeError: tuple indices must be integers, not str
-->End of Python script error report<--
  • 3
    Could you reduce this code to a [minimal example](http://sscce.org) that recreates the issue? It appears that `row` is a string - what were you expecting instead? – jonrsharpe Jun 14 '14 at 15:39
  • @jonrsharpe well what I'm expecting is when I stored the list of channels and programme in a sqlite3 database, I want to pull the data from the database using with `SELECT` for the columns for each channel so I can print the data. How I can use the `SELECT` to select the columns called `channel, title, start_date, stop_date` to print the list of data? –  Jun 14 '14 at 15:43

2 Answers2

2

You are looping over each row in the result, then over each column. The columns are strings:

for channel_result in results:
    for row in channel_result:

So channel_result is a row (a tuple by default), then you loop over that with for row in channel_result. This makes each row object a single column value.

You appear to expect row to be a dictionary instead; that is not the case here. You could just print the row directly; the columns are listed in the same order as the original SELECT:

for row in results:
    programming = (channelMap[row[0]],) + row[1:]

If you really wanted a dictionary for each row, you'll have to tell sqlite3 to so by setting the row_factory attribute on the connection:

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

con = sqlite3.connect(profilePath)
con.row_factory = dict_factory

after which you use the one loop:

for row in results:

and row will be a dictionary with keys corresponding to the column names.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thank you very much for this, when I try the code I'm getting an error `NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS! Error Type: Error Contents: (u'101 ABC FAMILY ',) Traceback (most recent call last): File "C:\Users\user\AppData\Roaming\XBMC\addons\script.tvguide\test.py", line 1677, in onAction programming = (channelMap[row[0]], + row[1]) KeyError: (u'101 ABC FAMILY ',)`. Do you know why I'm getting an error? –  Jun 14 '14 at 15:53
  • @user3667173: Your `channelMap` dictionary has no such key. No wonder, because your code defines it as *empty*. – Martijn Pieters Jun 14 '14 at 15:54
  • I'm trying to print the data from the database. I can see that I'm using `channelMap = dict()` which it has no such key. How I can use `channelMap` to fetching the data from a database? –  Jun 14 '14 at 16:06
  • @user3667173: I don't know, *what is the purpose of `channelMap`*? You didn't write this code? You need to determine why you are using the dictionary *in the first place*. – Martijn Pieters Jun 14 '14 at 16:08
  • @user3667173: For looking at the database contents, you could perhaps just *remove the dictionary lookup*? – Martijn Pieters Jun 14 '14 at 16:09
  • I have tried to use the `OrderedDict` instead of `dict` but I still get the same result. I think I need to find where the database is located. The variable for the channelMap which it won't know where the database is located. Any idea? –  Jun 14 '14 at 16:28
  • Do you have any idea? –  Jun 14 '14 at 17:08
  • I have *no* idea what you are talking about, actually. But it looks like the original exception is solved isn't it? As for locating the database, that would be a *[different question](http://meta.stackexchange.com/q/43478)*, consider posting it separately. – Martijn Pieters Jun 14 '14 at 17:12
  • yeah that is what I'm trying to do to get it to solve. This is the same question what I'm asking for. I'm trying to access to the database to find the columns, but I'm getting an error. Please see my first post that I have updated the code and the error from the xbmc log. –  Jun 14 '14 at 17:32
  • @user3667173: your update shows you are still trying to treat `row` as a dictionary, instead of a tuple. Use `row[0]`, etc. as I have shown you already. – Martijn Pieters Jun 14 '14 at 18:50
  • Thank you very much, I can see it is being fixed. There is a problem. I'm getting an error `Error Contents: Error binding parameter 0 - probably unsupported type`. Please see the update post in my first post. –  Jun 14 '14 at 19:01
  • @user3667173: I am going to point you again to the [meta post about changing your question with every step](http://meta.stackexchange.com/q/43478); ask a *new question* for new problems. – Martijn Pieters Jun 14 '14 at 19:03
0

If I see it right, the error is pretty precise. Your return value should be a list of strings. And as such, you need to user integers for indices in that line. Python just simply doesn't know what to do with row['channel'], because there's no index 'channel' defined for row. The easiest is probably to try and print the value of row there, then you should be able to debug it.

Here are a the docs: https://docs.python.org/2/library/sqlite3.html#sqlite3.Cursor

Tim
  • 802
  • 1
  • 7
  • 15