Here's a thing that happens a lot to me: I'm doing some work, and as part of that work I need to run a command in my terminal that takes a little while. I run the command, look at it for about a second and then switch to doing something else – checking email, perhaps. I get deeply involved in my email checking, and then about twenty minutes later I switch back to the terminal and see the command has finished. For all I know, it finished nineteen minutes ago, and I was just too engrossed to notice it.
This is a big productivity sink for me, especially if the command happened to fail and need retrying. I'm not disciplined enough to just sit and watch the command, and I'm not prescient enough to add something to each invocation telling me when a command is done. What I want is something that alerts me whenever long running commands finish.
Well, that thing now exists, thanks to glyph's script that provides precmd and postcmd support to bash and a lot of help from Chris Jones of Terminator.
To use it right now:
$ bzr co lp:~jml/+junk/shell-tools
$ . shell-tools/long-running.bash
$ notify_when_long_running_commands_finish_install
You'll see that if you run a command that takes over 30 seconds to complete, it will pop up a notification, which should hopefully take you away from whatever it was you are doing and back to the task at hand.
If you look at the code, you'll see that it installs two hooks: precmd and preexec. preexec runs just before the shell launches a command, and precmd runs just before it prompts for the next command. Our preexec stores when the command was launched and the precmd checks to see if it finished within a certain time frame. If not, it sends out a notification.
Currently, you'll get a notification when you finish reading a long document, since the command finishes a long time after the command starts. Obviously this isn't ideal. I think the fix is to only send notifications when the shell doesn't have focus. Unfortunately, that's a little tricky and I think is going to be highly terminal specific.
Anyway, I'm a total shell newbie, so I'd love to know if there's any way this could be done better. Also let me know if you find this useful, or you know of someone who has already done this.
Mere Code
Hacking, Software Collaboration, Testing and Diverse Other Topics of General Interest to the Practicing Programmer
Monday, January 23, 2012
Monday, December 26, 2011
What are my projects?
Launchpad doesn't really have any good mechanism for letting you review a list of "your" projects.
That's partly because there are a lot of different ways that it could do it. You could be the maintainer of a project, or its driver, or its bug supervisor, or you might have commit access to its trunk branch. All of this could be direct, or through membership of a team. It's tough.
Since it's that time of year when I review my projects, responsibilities, goals and the like and start to figure out what I want to do next year, I want to figure out what are my projects on Launchpad.
Luckily, Launchpad has an API. I can't use it to figure out what projects I'm the maintainer of, but I can use it to figure out what trunk branches I have commit access to. The link has the Python code for the script.
Really, Launchpad should allow me to curate my own list of projects, with input to that list coming from all of the sources mentioned above, as well as arbitrarily selecting projects.
That's partly because there are a lot of different ways that it could do it. You could be the maintainer of a project, or its driver, or its bug supervisor, or you might have commit access to its trunk branch. All of this could be direct, or through membership of a team. It's tough.
Since it's that time of year when I review my projects, responsibilities, goals and the like and start to figure out what I want to do next year, I want to figure out what are my projects on Launchpad.
Luckily, Launchpad has an API. I can't use it to figure out what projects I'm the maintainer of, but I can use it to figure out what trunk branches I have commit access to. The link has the Python code for the script.
Really, Launchpad should allow me to curate my own list of projects, with input to that list coming from all of the sources mentioned above, as well as arbitrarily selecting projects.
Monday, November 21, 2011
pyflakes update
Thanks to radix, exarkun & dash, my branch to pyflakes to warn about duplicate definitions of classes finally landed. I did the work a year ago as an outrage-powered, opportunistic fix after I saw a co-worker struggle with tests weirdly not failing (Turned out it was a huge test module and there was another class at the bottom with the same name). I'm very happy to see it landed.
For those who haven't been paying attention, official pyflakes development is now taking place on Launchpad as part of the divmod.org project. The trunk of that project now has the best version of pyflakes known to man.
pyflakes is the best static Python checker. It's fast, and has very few false positives.
Update: A couple of people have asked me about lp:pyflakes. It's dead. It died when the divmorg.org trac instance died ages ago. Don't use it. To get pyflakes or any other divmod project, use lp:divmod.org.
For those who haven't been paying attention, official pyflakes development is now taking place on Launchpad as part of the divmod.org project. The trunk of that project now has the best version of pyflakes known to man.
pyflakes is the best static Python checker. It's fast, and has very few false positives.
Update: A couple of people have asked me about lp:pyflakes. It's dead. It died when the divmorg.org trac instance died ages ago. Don't use it. To get pyflakes or any other divmod project, use lp:divmod.org.
Thursday, November 10, 2011
Automatic packaging update
I just blogged on developer.ubuntu.com about the work we're doing with automatic packaging. Read it!
Friday, November 4, 2011
How to feel better (or, some tips on refactoring)
A few months back I gave a lightning talk at the Launchpad Thunderdome about how I do refactoring. It's very opinionated, and mostly applies to big, old code bases, but worth writing up anyway.
The core idea here is that very few things make me feel as good as deleting code. I love cleaning up code and the clean code base that results, and I'm sure that many others feel like me. As such, this is a guide on how to feel better.
1. Know your enemy
“Functionality is an asset, code is a liability”. Truer words were never spoken. Every line of code is a potential source of bugs and a barrier to understanding, and thus carries a maintenance cost.
Maintain an awareness of things that need refactoring. Here's a quick and incomplete list:
Yak shaving is "any seemingly pointless activity which is actually necessary to solve a problem which solves a problem which, several levels of recursion later, solves the real problem you're working on." (Jargon File)
A few of us have extended the concept beyond the "actually necessary" to include anything that's making the task at hand more difficult and less fun but is not worth fixing right now. Hence the yak stack. Here's how it works:
Whenever you come across something in your code base that is difficult to understand or that slows you down: make a note of it. When you've finished the task at hand, fix the problem. If you encounter other things that slow you down, write them down. Work through the list.
3. Every option is wrong
In a big, old code base, there are probably many, many areas that need refactoring. Don't worry about which is the "best" place to start – there is no best place.
4. Start from green, stay green
Never, ever refactor while your tests are failing. Refactoring is about changing the shape of code while preserving its behaviour. It's much harder to be sure you're keeping the behaviour if you are comparing one set of thirty tracebacks with another set of thirty tracebacks. Better to compare a passing ("green") test run with another passing test run.
Run tests frequently. More often then you think you should. Commit often – think of it like quick save in a tough level of a video game. It frees you up to experiment more and means you have less in your head at any one time.
5. Do not nest
Don't begin a refactoring while you are in the middle of another refactoring. If you find you must, use tools like 'bzr shelve' to store your current diff and then work from the clean head of your branch.
6. Keep moving, leave a trail
Don't get bogged down in details, otherwise you'll never finish. Literally. Someone will come along and distract you and before you know it, three months will pass and your refactoring branch will be full of conflicts. If you see something you are unsure of, mark it with a XXX or a FIXME or a TODO or whatever works for you and then continue with what you are doing.
Tools like 'bzr todo' can make it really easy to check to see if you've added any XXX comments.
7. Translate tests with care
As said above, refactoring is about changing the shape of code while preserving its behaviour. When you update tests, you risk changing your definition of the system's behaviour – so be careful.
8. Confront uncertainty with destruction
If you see some code and you are not sure if it's needed, delete it. Doesn't matter if it's a whole function or just an odd line. If you have a test suite, and it was important, that will catch the failure. If you have version control, and it was important, one of your collaborators will notice and revert the change.
If it was important and neither of these happened, then your whole project has learned something new about itself, and that's probably worth the hassle. (Oh, add tests & better docs after this happens.)
9. Good grep tools
Remember that symbols aren't only referenced from files that match *.py. In big code bases there are often other sorts of files that refer to symbols in the main code. In Launchpad, for example, we have ZCML and doctest files that refer to symbols. When you want to know how something is used or you want to rename something, make sure you use a grep command that actually finds everything.
Ideally, you should be able to run this command faster than you can think about wanting to do it.
Personally, I use 'bzr grep' a lot. Others recommend 'ack'.
10. There will be failures
Mentally prepare yourself for the fact that the first two or three full test runs after your refactoring will fail. This is especially important for code bases that have multi-hour test run times.
If you think this way, then you won't be as discouraged when it actually happens.
11. Finish the job
Busy people refactoring a big code base are often tempted to apply a refactoring to only a single part. For example, some useful function is extracted from repeated boilerplate in a few other functions. However, many, many other instances in the code base continue to use the repeated boilerplate.
This is almost worse than just leaving the repeated boilerplate. There are now two idiomatic ways of doing the activity. Further, other developers who work on other parts of the code base probably won't find out about it, and might end up repeating your refactoring. Ugh. How is anyone new expected to get to grips with this code?
Similarly, if a class, function or concept is renamed, rename it everywhere, especially in the documentation.
It's difficult and often tedious, but it really is worth taking refactorings to completion. Apply them to the whole code base, or not at all.
Note that I'm referring to completeness, not perfection. If you block on perfection, you never get anything useful done. If you aim for frequent incremental improvements, you soar.
12. Read these books
I highly recommend "Refactoring" by Martin Fowler and "TDD by Example" by Kent Beck. I stole many of these ideas from them.
The core idea here is that very few things make me feel as good as deleting code. I love cleaning up code and the clean code base that results, and I'm sure that many others feel like me. As such, this is a guide on how to feel better.
1. Know your enemy
“Functionality is an asset, code is a liability”. Truer words were never spoken. Every line of code is a potential source of bugs and a barrier to understanding, and thus carries a maintenance cost.
Maintain an awareness of things that need refactoring. Here's a quick and incomplete list:
- unused code – this can be deleted
- boilerplate – this should become a function or class
- wrong documentation – these should be updated
- two ways of doing something – perhaps there should be one
- bad names – change them to something that makes you think less
Yak shaving is "any seemingly pointless activity which is actually necessary to solve a problem which solves a problem which, several levels of recursion later, solves the real problem you're working on." (Jargon File)
A few of us have extended the concept beyond the "actually necessary" to include anything that's making the task at hand more difficult and less fun but is not worth fixing right now. Hence the yak stack. Here's how it works:
Whenever you come across something in your code base that is difficult to understand or that slows you down: make a note of it. When you've finished the task at hand, fix the problem. If you encounter other things that slow you down, write them down. Work through the list.
3. Every option is wrong
In a big, old code base, there are probably many, many areas that need refactoring. Don't worry about which is the "best" place to start – there is no best place.
4. Start from green, stay green
Never, ever refactor while your tests are failing. Refactoring is about changing the shape of code while preserving its behaviour. It's much harder to be sure you're keeping the behaviour if you are comparing one set of thirty tracebacks with another set of thirty tracebacks. Better to compare a passing ("green") test run with another passing test run.
Run tests frequently. More often then you think you should. Commit often – think of it like quick save in a tough level of a video game. It frees you up to experiment more and means you have less in your head at any one time.
5. Do not nest
Don't begin a refactoring while you are in the middle of another refactoring. If you find you must, use tools like 'bzr shelve' to store your current diff and then work from the clean head of your branch.
6. Keep moving, leave a trail
Don't get bogged down in details, otherwise you'll never finish. Literally. Someone will come along and distract you and before you know it, three months will pass and your refactoring branch will be full of conflicts. If you see something you are unsure of, mark it with a XXX or a FIXME or a TODO or whatever works for you and then continue with what you are doing.
Tools like 'bzr todo' can make it really easy to check to see if you've added any XXX comments.
7. Translate tests with care
As said above, refactoring is about changing the shape of code while preserving its behaviour. When you update tests, you risk changing your definition of the system's behaviour – so be careful.
8. Confront uncertainty with destruction
If you see some code and you are not sure if it's needed, delete it. Doesn't matter if it's a whole function or just an odd line. If you have a test suite, and it was important, that will catch the failure. If you have version control, and it was important, one of your collaborators will notice and revert the change.
If it was important and neither of these happened, then your whole project has learned something new about itself, and that's probably worth the hassle. (Oh, add tests & better docs after this happens.)
9. Good grep tools
Remember that symbols aren't only referenced from files that match *.py. In big code bases there are often other sorts of files that refer to symbols in the main code. In Launchpad, for example, we have ZCML and doctest files that refer to symbols. When you want to know how something is used or you want to rename something, make sure you use a grep command that actually finds everything.
Ideally, you should be able to run this command faster than you can think about wanting to do it.
Personally, I use 'bzr grep' a lot. Others recommend 'ack'.
10. There will be failures
Mentally prepare yourself for the fact that the first two or three full test runs after your refactoring will fail. This is especially important for code bases that have multi-hour test run times.
If you think this way, then you won't be as discouraged when it actually happens.
11. Finish the job
Busy people refactoring a big code base are often tempted to apply a refactoring to only a single part. For example, some useful function is extracted from repeated boilerplate in a few other functions. However, many, many other instances in the code base continue to use the repeated boilerplate.
This is almost worse than just leaving the repeated boilerplate. There are now two idiomatic ways of doing the activity. Further, other developers who work on other parts of the code base probably won't find out about it, and might end up repeating your refactoring. Ugh. How is anyone new expected to get to grips with this code?
Similarly, if a class, function or concept is renamed, rename it everywhere, especially in the documentation.
It's difficult and often tedious, but it really is worth taking refactorings to completion. Apply them to the whole code base, or not at all.
Note that I'm referring to completeness, not perfection. If you block on perfection, you never get anything useful done. If you aim for frequent incremental improvements, you soar.
12. Read these books
I highly recommend "Refactoring" by Martin Fowler and "TDD by Example" by Kent Beck. I stole many of these ideas from them.
Over to you
This was very much just a dump of how I do refactoring when hacking on Launchpad. I'm always keen to learn more, and would love to hear about what works for you.
Wednesday, September 14, 2011
testtools 0.9.12 out
testtools 0.9.12 has just been released!
It's a huge release, this one. We normally try to release much more frequently, but for this release I wanted to wait until all of our known unicode handling bugs were fixed. Today, Martin [gz] finished off his heroic branch to fix up
In addition to all of the unicode fixes, we've really cleaned up the way test failures are displayed. A lot of the boilerplate around the traceback has been removed, a lot of levels of the stack are gone (although you can get them back if you want), and
For me, this release is the one where using matchers becomes really and properly fun. As such, all of our
Of course, we have our usual raft of fixes, helpers and new matchers too. The full changelog is on Launchpad.
In addition to Martin [gz], thanks to Christian Kampka, Robert Collins and Canonical for making this release what it is.
If you're new to testtools, it's basically a way to do serious, tasteful unit testing in Python.
Documentation lives at http://testtools.readthedocs.org/en/latest/.
PyPI: http://pypi.python.org/pypi/testtools
All development takes place on Launchpad: https://launchpad.net/testtools
Join us on #python-testing on Freenode
We don't currently have a release PPA, but we do have a daily builds PPA. The trunk is kept stable using Jenkins, so it's fairly safe to use.
It's a huge release, this one. We normally try to release much more frequently, but for this release I wanted to wait until all of our known unicode handling bugs were fixed. Today, Martin [gz] finished off his heroic branch to fix up
assertThat, and I figured it was time to release.In addition to all of the unicode fixes, we've really cleaned up the way test failures are displayed. A lot of the boilerplate around the traceback has been removed, a lot of levels of the stack are gone (although you can get them back if you want), and
assertThat is way less repetitive. This all really adds up. If you're using an old release, you want to upgrade right now. Honest.For me, this release is the one where using matchers becomes really and properly fun. As such, all of our
assertFoo methods are now implemented in terms of matchers.Of course, we have our usual raft of fixes, helpers and new matchers too. The full changelog is on Launchpad.
In addition to Martin [gz], thanks to Christian Kampka, Robert Collins and Canonical for making this release what it is.
If you're new to testtools, it's basically a way to do serious, tasteful unit testing in Python.
Documentation lives at http://testtools.readthedocs.org/en/latest/.
PyPI: http://pypi.python.org/pypi/testtools
All development takes place on Launchpad: https://launchpad.net/testtools
Join us on #python-testing on Freenode
We don't currently have a release PPA, but we do have a daily builds PPA. The trunk is kept stable using Jenkins, so it's fairly safe to use.
Friday, September 9, 2011
doctest really isn't very good
I just got sick of trying to decode obtuse doctest diff errors when using NORMALIZE_WHITESPACE and ELLIPSIS options. Although doctest gives you hooks to do something about this, it's really hard to actually write the logic.
See, NORMALIZE_WHITESPACE also normalizes line breaks, and '...' can match across multiple lines. That means that you can't take a line-based approach, which makes it really hard to clean up a diff. Anyway, here's my attempt: https://code.launchpad.net/~jml/testtools/better-doctest-output-checker/+merge/74842
It's a pain, because both of them would be very useful without their line-spanning behaviour. I guess without the line-spanning behaviour of '...' there'd be no way to indicate multiple lines of crap in output.
My suggestion in the mean time? Don't use doctest.
See, NORMALIZE_WHITESPACE also normalizes line breaks, and '...' can match across multiple lines. That means that you can't take a line-based approach, which makes it really hard to clean up a diff. Anyway, here's my attempt: https://code.launchpad.net/~jml/testtools/better-doctest-output-checker/+merge/74842
It's a pain, because both of them would be very useful without their line-spanning behaviour. I guess without the line-spanning behaviour of '...' there'd be no way to indicate multiple lines of crap in output.
My suggestion in the mean time? Don't use doctest.
Subscribe to:
Posts (Atom)
Blog Archive
-
►
2010
(68)
-
►
November
(14)
- testtools manuals
- Tests that print stuff
- Boiling kettles, unit tests and data
- Big or small?
- "Don't Make Me Think", thoughts for Launchpad
- Reviewing specs, rock on!
- Having an extra feature never hurts, rebutted
- And then what?
- Make it really easy to fix bugs on Ubuntu
- What else have you got?
- Ubuntu in a VM on OS X?
- Still going
- What to do, what to do
- Launchpad and UDS-N
-
►
November
(14)
