I’m Surya Nallu, a 3rd year Computer Science specialist student at the University of Toronto. Past summer I was excited to be a part of Google’s Summer of Code where in I got the opportunity to work on a project; that also introduced me to Django. Django’s elegant way of representing the components within the MVC framework is hands down awesome. I liked the experience so much that I wanted to continue working on a similar project during the school term. Fast forward and it’s been the same fun ride with ReviewBoard so far.
To get a feel of the code-base and to grasp the workflow, we were encouraged to find and fix some easy bugs during the three day long sprint at Facebook. I started off with checking some bugs on the backend and fixed a simple bug involving truncation of whitespace characters in an email field. How easy was it? As easy as calling .strip() on a variable. I sent the code for a review and it was pushed to the repository. But that’s not the point. It was my first bug fix and it does, indeed feel awesome to realize that your one line change will be implicitly used by a wide array of people.
The Extension Browser
While going through the potential list of projects the one that I was most interested was in developing an extension browser module for ReviewBoard. Given that I was comfortable with Django and preferred the back-end, I was stuck on pursuing the same. What is it? It’s a module on the ReviewBoard administration end, which lets you browse extensions (from a yet to be store — which will serve as a directory of extensions available) and install them right away. It’s analogous to WordPress’ automatic plugin installation. Why is it needed? First, since anyone can make an extension for ReviewBoard as a potential administrator you don’t possibly know all the extensions that exist. Second, as of now, you have to manually install the extension (which is ultimately a Python egg, given that Django runs on Python) on the server — which involves you to SSH into the server and perform the installation. This isn’t ideal. By creating an in-application extension manager, the administrators have the convnience of finding and installing an extension of their choice on-the-fly. No SSH, direct access to the server or technical know hows are required. Just find an extension and install.
Under the hood, the module would communicate with an API on the (yet to be) extension store and expect JSON responses. You get to specify what kind of extensions you’re looking for and are presented with the search results. You then have the option to look into more details for a particular extension or to install it. Installation is handled on the back-end through invoking easy_install within RevewBoard. If everything goes well, your new extension is up for use.
The progress so far: YouTube screencast
Initially upon taking up the project, one of the bugs that had been already reported needed attention. The bug was that upon installing an extension, you had to re-start the server (the development server or the appropriate WSGI platform) for the installation to take effect. You can see why this was something that needed to be fixed right away — on-the-fly installations from the extension browser module won’t take effect immediately. I started looking into it during the sprint and it took a while for us (Christian, Steven and I) to figure out what exactly was causing it in the first place. What was the problem?
Aside: When easy_install is used to install a package (in our context – the extension), the package/extension is made exposed to ReviewBoard with the help of entrypoints. The way I see it, it’s a registry of installed Python modules with each package associating itself with one or more entrypoints. The entrypoint associated with ReviewBoard is “reviewboard.extensions”; so any package that advertises itself to this entrypoint is accessible within ReviewBoard (and can be treated as an extension).
The issue technically here was that upon installing an extension, the extension wasn’t visible within the ReviewBoard’s extension entrypoint immediately. If we restarted the test server, the entrypoints got updated. Okay, so we figured (after a couple of searches and reading up resources) that the problem was with the package not being activated within the entry point and hence not being accessible instantly. We ended up reading through this thread and figured that’s the exact problem we were facing. We went ahead and applied the fix only to find it still not working. It became clear eventually that something specific to ReviewBoard was further causing the problem. How did we figure where?
We had to narrow down the problem to its root. Since we were calling easy_install directly within a python script, our first guess was that doing so was creating a problem; since usually easy_install is invoked through the shell. We created a test python script emulating exactly what we wanted and it worked; the entrypoints were getting updated as it was stated in the StackOverflow thread. Alright, narrowed down a little deeper. Next point was to see if Django itself was inhibiting something. So I emulated the same process within a test Django app and it worked fine. Okay, so Python’s good, so is Django. This confirmed that the ReviewBoard codebase was doing something special (or rather weird!). ReviewBoard (Djblets to be specific) provides a convenience function that lets you iterate through its extensions entrypoint. I then manually iterated and printed through all the packages that were present in this entrypoint (post an installation) and the new extension didn’t show up. To confirm again, I accessed the entrypoint directly myself (this time, not through the convenience function) using Python’s pkg_resources module and voila the new extension did show up now. So we clearly realized that the problem was the way the class holding the convenience function was handling the entrypoint (Djblets/extensions/base.py). It turned out that a stale line of import had no effect and it was creating the problem. Removing it, everything worked well.
Here are some tips that I personally find effective to be productive with working on ReviewBoard (or generally UCOSP itself):
- Find a good chunk of time to work on it. Having a continuous chunk of hours is way better than having small blocks of them split across the week. I typically prefer to spend a whole day in a week as a result and it helps me keep the momentum. It’s especially bad when you’re having all these nice ideas fly through your head about your implementation and you’ve to quickly stop and switch to some other work.
- When in doubt, ask! Though I’m fairly comfortable with Django, I often find myself not remembering the exact specifics of it. Django has pretty awesome documentation on everything you’d need. Moreover, if the problem is too specific chances are someone else has encountered the same problem before and it’s up on StackOverflow (that’s how we found the thread linked above in “Starting trouble” — I just Google’d “easy_install without restart”). Lastly, ping your mentors whenever you’re stuck. I often think of approaches that seem very elegant at first but after a quick discussion, it turns out there are better ways.
- Although this can be contested, printing for debugging is okay. While I love debuggers, it’s not all that easy (and often not necessary, especially) to quickly inspect a variable or a function you wrote on the server side with a debugger for Django. I add a raw_input() statement immediately followed by a print statement so that the values I’m interested in show up on the console running the test server and wait for my go (raw_input() will block) to continue processing ahead.
That’s all I have for now! I’m excited that the extension browser module would soon be a useful addition to ReviewBoard.