<p>Basically, I've written an API to www.thetvdb.com in Python. The current code can be found <a href="http://github.com/dbr/tvdb_api/tree/master/tvdb_api.py" rel="noreferrer">here</a>.</p>

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

<pre><code>print tvdbinstance[1][23]['episodename'] # get the name of episode 23 of season 1
</code></pre>

<p>What is the "best" way to abstract this data within the <code>Tvdb()</code> class?</p>

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

<p>Then I just stored the data by doing <code>self.data[show_id][season_number][episode_number][attribute_name] = "something"</code></p>

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

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

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

<p>The problem now is it's presenting itself as a dict, but doesn't have all the functionality, and because I'm overriding the <code>__getitem__</code> and <code>__setitem__</code> functions, it's easy to accidentally recursively call <code>__getitem__</code> (so I'm not sure if extending the <code>Dict</code> class will cause problems).</p>

<p>The other slight problem is adding data into the dict is a lot more work than the old <code>Dict</code> method (which was <code>self.data[seas_no][ep_no]['attribute'] = 'something'</code>). See <code>_setItem</code> and <code>_setData</code>. 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.</p>

<p>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 <code>ShowContainer</code>/etc classes with <code>Dict</code> cause problems?</p>

[{'answer_id': 6125, 'author': 'Jonathan Works', 'author_id': 309844, 'author_profile': 'https://Stackoverflow.com/users/309844', 'pm_score': 2, 'selected': False, 'text': '<p>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 <a href="http://docs.python.org/lib/module-sqlite3.html" rel="nofollow noreferrer">sqlite3</a></p>\n\n<hr>\n\n<p>If you don\'t want to use SQLite you could do an array of dicts.</p>\n\n<pre><code>episodes = []\nepisodes.append({\'season\':1, \'episode\': 2, \'name\':\'Something\'})\nepisodes.append({\'season\':1, \'episode\': 2, \'name\':\'Something\', \'actors\':[\'Billy Bob\', \'Sean Penn\']})\n</code></pre>\n\n<p>That way you add metadata to any record and search it very easily</p>\n\n<pre><code>season_1 = [e for e in episodes if e[\'season\'] == 1]\nbilly_bob = [e for e in episodes if \'actors\' in e and \'Billy Bob\' in e[\'actors\']]\n\nfor episode in billy_bob:\n    print "Billy bob was in Season %s Episode %s" % (episode[\'season\'], episode[\'episode\'])\n</code></pre>\n'}, {'answer_id': 6805, 'author': 'Mike Minutillo', 'author_id': 358, 'author_profile': 'https://Stackoverflow.com/users/358', 'pm_score': 0, 'selected': False, 'text': "<p>I have done something similar in the past and used an in-memory XML document as a quick and dirty hierarchical 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.</p>\n<p><strong>NOTE:</strong> I'm not a Python guy so I don't know what your xml support is like.</p>\n<p><strong>NOTE 2:</strong> 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.</p>\n"}, {'answer_id': 8165, 'author': 'Bartosz Radaczyński', 'author_id': 985, 'author_profile': 'https://Stackoverflow.com/users/985', 'pm_score': 0, 'selected': False, 'text': "<p>I don't get this part here:</p>\n\n<blockquote>\n  <p>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)</p>\n</blockquote>\n\n<p>There is a way to do it - called <strong>in</strong>:</p>\n\n<pre><code>&gt;&gt;&gt;x={}\n&gt;&gt;&gt;x[1]={}\n&gt;&gt;&gt;x[1][2]={}\n&gt;&gt;&gt;x\n{1: {2: {}}}\n&gt;&gt;&gt; 2 in x[1]\nTrue\n&gt;&gt;&gt; 3 in x[1]\nFalse\n</code></pre>\n\n<p>what seems to be the problem with that?</p>\n"}, {'answer_id': 9080, 'author': 'dbr', 'author_id': 745, 'author_profile': 'https://Stackoverflow.com/users/745', 'pm_score': 0, 'selected': False, 'text': '<p>Bartosz/To clarify "This worked okay, but there was no easy way of checking if x[3][24] was supposed to exist or not"</p>\n\n<p><code>x[\'some show\'][3][24]</code> would return season 3, episode 24 of "some show". If there was no season 3, I want the pseudo-dict to raise tvdb_seasonnotfound, if "some show" doesn\'t exist, then raise tvdb_shownotfound</p>\n\n<p>The current system of a series of classes, each with a <code>__getitem__</code> - Show checks <code>if self.seasons.has_key(requested_season_number)</code>, the Season class checks <code>if self.episodes.has_key(requested_episode_number)</code> and so on.</p>\n\n<p>It works, but it there seems to be a lot of repeated code (each class is basically the same, but raises a different error)</p>\n'}, {'answer_id': 10778, 'author': 'Bartosz Radaczyński', 'author_id': 985, 'author_profile': 'https://Stackoverflow.com/users/985', 'pm_score': 4, 'selected': True, 'text': '<p>OK, what you need is <code>classobj</code> from new module. That would allow you to construct exception classes dynamically (<code>classobj</code> takes a string as an argument for the class name). </p>\n\n<pre><code>import new\nmyexc=new.classobj("ExcName",(Exception,),{})\ni=myexc("This is the exc msg!")\nraise i\n</code></pre>\n\n<p>this gives you:</p>\n\n<pre><code>Traceback (most recent call last):\nFile "&lt;stdin&gt;", line 1, in &lt;module&gt;\n__main__.ExcName: This is the exc msg!\n</code></pre>\n\n<p>remember that you can always get the class name through:</p>\n\n<pre><code>self.__class__.__name__\n</code></pre>\n\n<p>So, after some string mangling and concatenation, you should be able to obtain appropriate exception class name and construct a class object using that name and then raise that exception.</p>\n\n<p>P.S. - you can also raise strings, but this is deprecated.</p>\n\n<pre><code>raise(self.__class__.__name__+"Exception")\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/5966', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/745/']