Entertainer Moves To Launchpad (Or Returns?)

April 30, 2008 No Comments
Tagged as: entertainer

When I first approached Lauri about working on Entertainer, he had released Entertainer on Launchpad. Not long after I started working on the project, Lauri had problems getting bazaar to work with Launchpad, and so we move to Google Code. We've been there since then.

However, recently, while working on the new backend-refactoring stuff, I found that svn was just too lacking in allowing me to merge in continuing development on trunk into my refactoring branch. It then got to the point where I dreaded the actual merging back into trunk. I think much of this was because I had been using distributed version control systems consistently in the work I was doing for my clients, and really enjoyed it.

After chatting with the rest of the developers, we decided we should move to Launchpad. With the option of having vcs-imports, it was a good option, for many reasons. After all, the idea of Launchpad is to have all open source projects in one place anyway.

So, the basis of this blog post is this: Entertainer can now be found at http://www.launchpad.net/entertainer. Mentoring is available to anyone who would like to contribute...

March Entertainer Sprint Recap

March 9, 2008 No Comments
Tagged as: entertainer

This weekend, all the Entertainer developers got together and sprinted again. This month's sprint had TONS more work done, as we pushed through to get closer to a 0.1 release. I wouldn't say we'll see that 0.1 release in the next month, but we are much closer now.

Joshua worked on getting a working weather module into Entertainer. The 'Weather' option in the main screen has always led to a blank screen. Currently, the 'Weather' option is gone from the main screen, but only because the UI is being worked on, and the flow that will be followed to set up weather is being worked out. However, the backend code has been completed, and it's ready to be used once those issues are worked out.

Lauri refactored TONS of the UI code, to make it more readable (I will agree it is more readable now), and the UI now features navigation tabs to make things a little clearer to the user. The UI has been a source of much deliberation between developers since one of the main goals of Entertainer is to make it "so easy a caveman can do it." Lauri has done a wonderful job at paying attention to the small details that push Entertainer that extra mile.

Matt has also been working tirelessly to get the clutter API figured out, and has been fixing bugs and writing more tests. It's getting to the point that he owns more of the test framework than anyone else, and he probably knows more of the codebase than anyone now, since he's been writing most of the unit tests to bring our coverage up.

I've been working tirelessly on a side branch, out of everyone's way, so my work wasn't seen much. The current backend for Entertainer has needed some love for a quite a while, so I've been making a LARGE rafactoring effort there. The new backend will feature an ORM, so that it's easier to write tests against our database, as well as easier to work communicate with the database. It'll also feature a refactored and redesigned schema that will allow for quicker access to the database.

As for development stats, we saw 38 commits overall (revs 276-314), comprising of 1,837 new lines of code, and 1,723 changed lines of code. Most of that code was refactoring, so we only saw one new test all weekend (although I believe the release of a certain video game may have hampered development on that front.... :)

pylirc2 : Taking Over pylirc

February 29, 2008 No Comments

I've been trying to get lirc support into Entertainer the last few days, and while SOME of pylirc is still able to work, it's incredibly old. I contacted to current maintainer about this, and haven't heard back from yet. Since I need to move quickly to get this module updated, I have mirrored the Sourceforge CVS repository and converted it into a Mercurial repository. It can be found at:

http://hg.ironlionsoftware.com/pylirc2

Please note that I don't intend to fork the project or anything like that. I just plan to continue it's maintenance, specifically for Entertainer, but for the use of anyone who would like to have python bindings to lirc.

Python and Test Driven Development with unittest.TestCase

I've been posting a lot about test driven development recently, and I got an email from a reader who asked me to go into detail on how I've been going about discovering and working with tests. I think this type of post would have helped me develop the "test first" mindset so much earlier in my career, so I'm sitting down to actually detail exactly how I'm learning about this world that I've always heard about, but only now have visited. I guess an alternate title for this post could be "Python Unit Testing 101"

Because I try to spend at least 10 hours a week on Entertainer, and it's already got a pretty good test base that I have lots of experience in (because I wrote a large chunk of it), I think it would in everyone's best interest if I used a new Entertainer test as an example. If you would like, you can check out the code and see exactly what I've been doing by looking in trunk/src/tests. To run the tests, just navigate to the test directory, and type ./run_tests.py You'll see the tests grind away, telling you which ones passed and which ones didn't (hopefully, all of them are passing when you check out the code...)

Abstraction - The Seed of an Idea

I've been maintaining (or trying to maintain) the thumbnailers, ImageThumbnailer and VideoThumbnailer. They both inherit from an empty abstract class Thumbnailer. Recently, when trying to hunt down a bug, I noticed similar code in both VideoThumbnailer and ImageThumbnailer that could easily be rafactored to an already existing Thumbnailer class. For reference, I actually found this while hunting down a bug in ImageThumbnailer, and writing a test to make sure the bug stayed squished. As I planned out exactly what the Thumbnailer abstract class needed to look like, I started thinking about the test I needed to write first.

The abstract Thumbnailer class looked like this: thumbnailer.py

Planning - Writing the Test

The most important thing to remember about TDD is that your tests describe the way your code should behave, not the way it does behave. For instance, if you find a place where the code should be refactored to behave differently, write the test that way, make sure it fails in the way you expect, and then you can refactor the code to pass the test. That's what I did with the ThumbnailerTest. Since there wasn't any code/logic in the Thumbnailer class, all the tests technically should fail. But I had a few things in mind in refactoring:

  1. The Thumbnailer should have logic to tell what type of thumbnail it will create, so it can set it's destination path properly. The types are determined by what folders exist in the thumbnails config directory (currently image, video, and recording). It should throw an exception if it's an invalid type.
  2. The Thumbnailer should only try to thumbnail an image or video that exists. It should throw an exception otherwise.
  3. It should make sure that the classes that should be overridden by the child classes exist. I'll use a fun little technique for this that I learned only recently.

Obviously, I now have my tests. Let's look at item one. I like to break that test up into two tests, one that tests that each type can be properly parsed and recognized as valid, and one test that throws junk data as the type, and ensures that it throws an exception. I created my test by inheriting from unittest.TestCase, creating a setUp() method, containing only a debug flag (which you can use to make sure your test is working...), and then I start creating my tests.

The result of these tests is the following: Thumbnailer_test.py

On A Tangent - The Test Runner

Before we run the new test in the test suite, take the time to look at the run_tests.py script. run_tests.py

You'll notice that the script searches through the current directory for python files (except those in the blacklist), and using the unittest.TestLoader and unittest.TestSuite classes, loads the those files as modules, and then runs the TestCase child objects. The output of this script is the results from the tests. It's nothing terribly complicated, but then again, if your tests or test harness are complicated, you probably ought to change the implementation.

An alternative to the script used in Entertainer is python-nose. By installing it, you can run each test file yourself by doing nosetests <filename>. It will automatically find the unittest.TestCase instances in your file, and run them, printing the results to the terminal.

The Test Is Failure

Back to the tests at hand, you'll notice they all fail. This is good! If they passed, something is definitely wrong with your tests. Look at the errors for the failed tests and make sure they are what you expect. For instance, if you're trying to call a method that doesn't exist, make sure you've got an AttributeError exception, etc. If they are failing the way you expect, then you can consider your tests to be working properly. Now your job is to hack on the class you're testing until it passes the tests.

While you're writing this class, hopefully you're starting to see the value of the test. It was when I was working on the VideoThumbnailer that I started realizing how great TDD is. Instead of firing up the UI every time I made a small change to the VideoThumbnailer, I just ran the test to see if it was generating thumbnails. So instead of making a change, firing up the ui, navigating to the videos, and checking for thumbnails (and at the time, the UI was in a great state of flux at the time, and was only working for me every once in a while. Having the tests meant making a change, running the test runner to see if the test passed. No dependence on the UI working or anything of the sort.

Your Code Works Because the Test Says It Does

After a quick iteration of work (because you've got the test to run instead of the use case), you've now got working code. You know it's working because your test is passing. You know your test is working because you wrote it, and watched it fail exactly the way it should.

The Thumbnailer class now looks like this: thumbnailer.py

Now you can feel safe in committing your refactored code. Because I already had tests for ImageThumbnailer and VideoThumbnailer written well, the tests required no changes in order to test the code I removed to the abstract class. The general rule is that your class' interfaces should be simple, and shouldn't have to know about the "guts" of another class. Because it was constructed well, the tests worked without a problem.

As you write tests, remember that you're writing code still. I've seen lots of people write the tests and see them pass, and then work on the code, and the tests fall out of maintainability. When you make drastic changes to your code, make the tests reflect that, or rather, make the tests reflect the changes first. When you have tests, your codebase is 2-4 times the size of the code that actually gets deployed, so you've got more code to maintain. However, hopefully the maintainence of the code gets easier as the testing gets better (and if it doesn't, something is wrong with either you, or your codebase).

30 Second Epiphany : Developing for Standards, etc.

February 21, 2008 No Comments

I was looking through the bug list for Entertainer when I stumbled on issue #31. This bug must have come in during our sprint, and I just skimmed over it. I decided I would look into the bug, and was making a comment to go along with accepting the bug, This is where my personal reflection of 30 seconds started.

Initially, I thought, "well, just because it's the standard doesn't necessarily mean that it's the way we should go. Look at all these other apps that don't adhere to the standard." This didn't sound right, and my brain threw an exception. How many companies think that way, leaving the rest of the world to just complain. I caught the exception, and thought "well, we should review the standard, and see how well it is adopted now, and whether or not we should consider it now, or do it down the line." This also didn't make sense to me. How long do you wait before you implement the standard in your app? I finally rested on "We should jump at the chance to fall in line with standards."

Entertainer is an open source project, licensed under the GPL. This means that we're all about open standards as well, and making it easy for everyone to be compatible. If Entertainer, as an open source project, decides to go against those open standards, than we aren't that far ahead of proprietary software. I think every open source project should jump at the chance to adhere to open standards, and make it a priority. Then we can truly call our software "open."

Test Driven Refactoring

I've been blogging about this a lot recently, mostly because it's now completely part of my life, but I'd like to just say Holy crap test driven development is awesome! The reason for this exclamation now is that I was trying to find out why two tests were failing (because the tests were written to adhere to how the class is supposed to work, instead of how it does work).

While debugging the class, I noticed that every function, including the constructor, was opening a handle to the sqlite database, reading in data, and then closing it. I began refactoring to make the code clear (which actually led to understand the why and where of the bugs I was trying squish. After making some necessary changes, I ran the test script, and noticed I had more failures than before, so I refactored some more, and ran the tests again. Each time, there were few issues, until eventually, I had all the tests passing (including the two that weren't passing before).

Along with that, the class methods are completing an average of more that twice as fast (because it's using the already opened handle to the sqlite database, instead of creating a closing a new one each time. The file went from 620 lines to 584, with some additional functionality, like __str__() methods and such for the class. The greatest feat, though, is that I completed this all in about half an hour.

I am absolutely sold on test driven development.

Entertainer Sprint Weekend One Recap

February 10, 2008 No Comments

On Friday, I decided to plan a sprint for the weekend. It required a little more coordination than I originally expected. With the developers strewn from Finland and Poland, to the UK, to Maryland, and finally, myself, in good ol' -7 GMT, there's a 9 hour difference. This required me to get up quite early on Saturday, and spend a whole weekend hacking on Entertainer.

After a whole weekend working with two other developers, and very good up-and-coming developer/tester, and the occasional testers dropping into the IRC channel to say hi, file a bug, and then leave, we got a lot accomplished. I was finally able to complete a working VideoThumbnailer class (which meant reading every gstreamer doc, and tons of blogs, and still learning from trial and error). Joshua Scotton was able to complete the news reader portions, with support for Liferea feeds, etc. Lauri has successfully written cd playback, and is hoping to get DVD playback in soon. We also now have 10x the tests than we had on Friday evening (from 4 to 41), with all but two passing, and four of which were tests that revealed bugs (and the two that aren't passing are among them). A total of 1,728 new lines of code were introduced into the codebase, over 25 commits. Documentation was updated and confirmed to be detailed. 10 new bugs were filed, and 7 reported bugs were closed. A large amount of code was refactored using our newfangled test framework, and we were able to find a few issues with architecture and coding practices, optimizing as we went.

Overall, the sprint was an absolute success. We were able to talk to eachother, and determine what was required for a 0.1 "preview" release, and what we could push off for another version. I made some great progress on converting all of our current ASCII string data to UTF-8, although there is still a bit of room for improvement (and I'll be working on that off-and-on for the next while).

I'm hoping that we can sprint once a month on Entertainer, and really get a neat, polished app soon.

TDD By Accident

February 5, 2008 No Comments

I've been working on a new project, called Entertainer, which is aiming to be similar to MythTV, but with a featureset devoted more to end users than MythTV is. It's got a pretty slick interface (although some of the interface code is based on an alpha library right now), and has been quite educational for me, especially since I've been working specifically with the gstreamer python bindings.

Recently, I've been working on a VideoThumbnailer for Entertainer using gstreamer. While I worked on it, another developer broke the actual GUI code (or rather, a widget from a library Entertainer's GUI depends on broke), which completely halted me from testing it (Entertainer is pre-alpha). This was okay, because I had only been reading documentation on the Gstreamer, and hadn't quite gotten to code yet. However, before I got to coding, I decided that I needed a way to the thumbnailer, and with the frontend broken, I couldn't very well do that. So I decided to write a unit test.

After stubbing out the unit test, I got to work. Originally, I was using nose and then eventually just creating my own test runner, to eliminate dependencies (we already have a ton of them...). I put a lot of work into the test framework, making sure output was clean and everything.

It was only after all of this, and I was working on the thumbnailer and running the unittest to see if it worked that I realized I was doing test-driven development. It was something I had always read about, but had never done. I will swear by it now. It's made my life so simple. Even now that the GUI in Entertainer is working again, I don't much care to use it to test. I've got a unittest that tells me all I need. If I need more, I'll modify the unittest.

What's even better is that the rest of the Entertainer developers are also getting on the bandwagon. We even have a developer who's never written python before that will be writing the tests for a lot of the code we have. How cool?