views:

251

answers:

5

Basically, I've written an API to www.thetvdb.com in Python. The current code can be found here.

It grabs data from the API as requested, and has to store the data somehow, and make it available by doing:

print tvdbinstance[1][23]['episodename'] # get the name of episode 23 of season 1

What is the "best" way to abstract this data within the Tvdb() class?

I originally used a extended Dict() that automatically created sub-dicts (so you could do x[1][2][3][4] = "something" without having to do if x[1].has_key(2): x[1][2] = [] and so on)

Then I just stored the data by doing self.data[show_id][season_number][episode_number][attribute_name] = "something"

This worked okay, but there was no easy way of checking if x[3][24] was supposed to exist or not (so I couldn't raise the season_not_found exception)

Currently it's using four classes. ShowContainer, Show, Season and Episode. Each one is a very basic dict, which I can easily add extra functionality in (the search() function on Show() for example). Each has a __setitem__, __getitem_ and has_key

This works mostly fine, I can check in Shows if it has that season in it's self.data dict, if not, raise season_not_found. Check in Season() if it has that episode and so on.

The problem now is it's presenting itself as a dict, but doesn't have all the functionality, and because I'm overriding the _getitem_ and _setitem_ functions, it's easy to accidently recursively call _getitem_ (so I'm not sure if extending the Dict class will cause problems)

The other slight problem is adding data into the dict is a lot more work than the old Ddict method (which was self.data[seas_no][ep_no]['attribute'] = 'something'). See _setItem and _setData. It's not too bad, since it's currently only a read-only API interface (so the users of the API should only ever retrieve data, not add more), but it's hardly.. elegant..

I think the series-of-classes system is probably the best way, but does anyone have a better idea for storing the data? And would extending the ShowContainer/etc classes with Dict cause problems?

+2  A: 

Why not use SQLite? There is good support in Python and you can write SQL queries to get the data out. Here is the Python docs for sqlite3


If you don't want to use SQLite you could do an array of dicts.

episodes = []
episodes.append({'season':1, 'episode': 2, 'name':'Something'})
episodes.append({'season':1, 'episode': 2, 'name':'Something', 'actors':['Billy Bob', 'Sean Penn']})

That way you add metadata to any record and search it very easily

season_1 = [e for e in episodes if e['season'] == 1]
billy_bob = [e for e in episodes if 'actors' in e and 'Billy Bob' in e['actors']]

for episode in billy_bob:
print "Billy bob was in Season %s Episode %s" % (episode['season'], episode['episode'])
Jon Works
A: 

I have done something similar in the past and used an in-memory XML document as a quick and dirty hierachical database for storage. You can store each show/season/episode as an element (nested appropriately) and attributes of these things as xml attributes on the elements. Then you can use XQuery to get info back out.

NOTE: I'm not a Python guy so I don't know what your xml support is like.

NOTE 2: You'll want to profile this because it'll be bigger and slower than the solution you've already got. Likely enough if you are doing some high-volume processing then XML is probably not going to be your friend.

Wolfbyte
A: 

I don't get this part here:

This worked okay, but there was no easy way of checking if x[3][24] was supposed to exist or not (so I couldn't raise the seasonnotfound exception)

There is a way to do it - called in:

>>>x={}
>>>x[1]={}
>>>x[1][2]={}
>>>x
{1: {2: {}}}
>>> 2 in x[1]
True
>>> 3 in x[1]
False

what seems to be the problem with that?

Bartosz Radaczyński
A: 

Bartosz/To clarify "This worked okay, but there was no easy way of checking if x[3][24] was supposed to exist or not"

x['some show'][3][24] would return season 3, episode 24 of "some show". If there was no season 3, I want the pseudo-dict to raise tvdbseasonnotfound, if "some show" doesn't exist, then raise tvdbshownotfound

The current system of a series of classes, each with a __getitem__ - Show checks if self.seasons.has_key(requested_season_number), the Season class checks if self.episodes.has_key(requested_episode_number) and so on.

It works, but it there seems to be a lot of repeated code (each class is basically the same, but raises a different error)

dbr
+1  A: 

OK, what you need is classobj from new module. I cannot give you code sample at the moment, I'll try to do that in a feew hours. That would allow you to construct exception classes dynamically (classobj takes a string as an argument for the class name).

Edit: below a simple code sample that might help you

import new
myexc=new.classobj("ExcName",(Exception,),{})
i=myexc("This is the exc msg!")
raise i

this gives you:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.ExcName: This is the exc msg!

remember that you can always get the class name through:

self.__class__.__name__

so, after some string mangling ang concanetion you should be able to obtain appropriate exception class name and contruct a class object using that name and then raise that exception. HTH

P.S. - you can also raise strings, but this is deprecated.

raise(self.__class__.__name__+"Exception")
Bartosz Radaczyński