Thanks to Wari, pytddmon is now registered on Ohloh.
In my previous post, I mentioned a serious bug that had kept my motivation low since autumn 2011.
The bug is about renaming .py files. Imagine you have a unit test test_some.py. It is testing some.py, and when pytddmon is running, all tests are green. You decide you want to rename some.py to something.py because of reason(tm). Since test_some.py is doing import some, but some.py doesn’t exist anymore, there will be an exception when trying to run the tests in test_some.py – which in turn fails that unit test. That should make pytddmon sad and red, right?
Wrong! It does not – pyddmon stays green*!
That is why I call it the rename bug (link to issue page).
I found it extremely odd for a long time, and I had a clear memory of this working at some point of pytddmons history. So I tested for the existence of this bug in every single revision (>100!) of pytddmon going back all the way to the launchpad days. Not in a single version did pytddmon work as expected; the bug was there all the time.
So I gave up for awhile. And then later on I built the Monitor class and refactored, refactored, refactored. Still not red!!! What the hell was going on?
Then it hit me how stupid I am. It was the .pyc files! They are left beside the .py file and CPython/pytddmon loads them instead of the renamed file! Face palm!
Anyway, to make a long story short, this sort of thing clearly is something out-of-scope for pytddmon to care for. For example, the exact same (mis)behavior exists when using basic unittest running: python test_some.py will import some.pyc and not something.py. However, in Python3.2 the rename problem is non-existent: .pyc files behave differently. Read PEP3147 for details (thanks for hint on this Neppord!).
One more reason to start using Python3.2 more!
*this is not true if you are using Python3.2. Read the rest of the blog post to understand why!
Long time no see!
Pytddmon has been asleep for awhile. The plans for configurability from the autumn didn’t fly, not least because I found out about a serious bug which made me unmotivated to merge stuff into the objarni/pytddmon repository.
But beneath the surface some things has started to happen. In an attempt to understand the bug, I tried to simplify pytddmon.py as much as possible. That work resulted in a new class for file change detection called Monitor. The work to integrate that class is going on in the pytddmon_monitor_integration fork, and so far it has resulted in 30% less code — down from 800 lines to 550! Even though it actually didn’t solve the bug , I’m all for keeping the source small and neat, so I think I will merge that fork as soon as it feels stable enough, and make a new release at the same time.
But the bug remains unsolved. However, I have understood the nature of the bug, and actually it might not be possible to solve at all, or rather, not a problem which pytddmon should solve for the user. I’ll write a blog post about it some other time.
Since we’re so few developers, we’ve decided to drop support for Python2.6, and focus on 2.7 (keeping CPython3.2 running too). If this bugs you out, please make your voice heard either by commenting here, telling the pytddmon twitter account about it, or join the mailing list and tell us about it.
Oh yeah. Spam. I’ve had 500 spam comments since october. That is *way* too much administration, so I bit the sour apple and bought an Akismet key. So if you’ve added comments to this site and I haven’t answered, sorry. That problem doesn’t exist anymore.
I’ve added a page called ”How does it work” in the menu to the right, explaining the essentials of how pytddmon functions.
I’ve put together a road map for pytddmon development efforts until christmas 2011.
We’re finishing a major code refactoring effort, using the pylint tool to increase code readibility. We’re already up from 6/10 to 9.5/10, so we’re almost finished with this.
Discussions about the next upcoming major feature: config file. Basically we want to make changing the behaviour of test-discovery and the monitoring functionality a bit more user-configurable than changing the source code of pytddmon.
Implement config-file feature.
So what’s happened since June?
The summer passed without much development, but in August things started happening again. Samuel (and I to some extent) have implemented Recursive Test Discovery, but it is not tested enough (especially not on Python3) to be released just yet. That feature is even more important than the config file feature (IMHO), so we’ll release that as soon as it’s stable. Another small change that’s been happening behind the scenes is the file name change from ”pyTDDmon.pyw” to the more conventional ”pytddmon.py”.
Neppord has contributed a couple of patches the last few weeks. Apart from some code-cleaning (thanks!) and a bug-fix (even bigger thanks!) he has added doctest-support to pytddmon. Read more on the details of the cool standard Python module doctest here.
Since doctest-tests are ”embedded” in the definition of a function (or class) in Python, the natural thing to do would be to scan all *.py files in the current directory. However, after some discussion, we’ve decided not do to that, based on the rationale that importing (and thus executing) every *.py file in the current directory may lead to unwanted* side effects.
Here’s some code to explain this:
def double(x): ''' >>> double(5) 10 ''' return x*2
If that function is saved in ”test_some.py”, pytddmon will discoverd it automatically, like any unittest-based test.
However, the natural thing is to save it in a code file, not a test file. If you save it to ”unit.py”, pytddmon will not discover it. Instead, you will have to specify that you really want pytddmon to look into that file for tests:
python pyTDDmon.pyw unit.py
The new version can be downloaded via the Download link to the right. It includes Python3 support too!
* Even though the Python convention is to not do things when a module is imported (as opposed to being run as a script) via the following well-known idiom:
if __name__ == '__main__': main()
… we consider that knowledge a little bit too non-trivial, and thus decided against letting pytddmon implicitly run all *.py-code automatically. Of course, test_*.py files are still run implicitly, just as has always been the case for pytddmon.
I got really curious and cloned his fork ”Always on top”, and, just as the name implies, it forces the pyTDDmon window to stay on top of other windows. This is the essential line of code:
But – what a difference a row made!
This neat feature was only semi-available previously via the ”Always on top”-checkbox found in every Ubuntu-window*. I used to tick that box every time I booted pyTDDmon on Ubuntu. Annoying.
And such a checkbox is not even available on Windows, which made pyTDDmon really uncomfortable to use in that OS. I’m not sure how Mac OSX worked in this regard – but anyway, now pyTDDmon behaves like this out-of-the-box, as it should do.
So I want to say ”Thank you” to KrunoSaho, and mention that this fork was one of the reasons I realized pyTDDmon needed it’s own home on the internet.
BTW – stories like this is one of the reasons I love open source software!
* I guess it’s really a GNOME feature, but anyway.
I put together the first prototype of pytddmon autumn 2009.
The use of pygame for the GUI is like bringing a kitchen because you want a coffe-machine, since pygame includes image-loading & display, sound & music loading & playback, collission detection and more (it’s meant for 2d games development).
Anyway, the reason for this blogpost is to give credit to one of the first contributors to pytddmon: Fredrik Wendt. He helped me switch from pygame to Tkinter in the breaks inbetween seminars of the FSCONS2009.
Thanks for coercing me to do the inevitable and drop the kitchen, Fredrik!
I hacked away tonight, trying to make pyTDDmon support both Python 2 and 3 – at the same time. The last point is important, because I want pyTDDmon to stay a single-file distribution. I would say it worked better than I had expected.
Some of the changes I had to make includes:
1. ”import Tkinter” becomes ”import tkinter” in Python 3
2. def set_result(self, (green, total)) is not valid in Python 3. No support for ”tuple splitting”! Simple change: def set_result(self, green, total).
(don’t ask me why I used the tuple in the arguments of set_result. I have no good answer!)
3. All icon related code was commented out. It was not used anyway, and caused a hazard of encoding-problems (differences between Python 2 and 3 strings..)
I tested it with the following operating systems and Python versions:
- Windows + Python 2.7
- Windows + Python 3.2
- Ubuntu10.10 + Python 2.6
- Ubuntu10.10 + Python 2.7
- Ubuntu10.10 + Python 3.1
You can try this experimental version of pyTDDmon by downloading the development version of pyTDDmon.py. I am not daring enough to publish it as the stable version yet