My first python3 script

I’ve been hacking on other people’s python3 code for a while doing porting and bugfixes but so far my own code has been tied to python2 because of dependencies. Yesterday I ported my first personal script from python2 to python3. This was just a simple, one file script that hacks together a way to track how long my kids are using the computer and log them off after they’ve hit a quota. The kind of thing that many a home sysadmin has probably hacked together to automate just a little bit of their routine. For that use, it seemed very straightforward to make the switch. There were only three changes in the language that I encountered when making the transition:

  • octal values. I use octal for setting file permissions. The syntax for octal values has changed from "0755" to "0o755"
  • exception catching. No longer can you do: except Exception, exc. The new syntax is: except Exception as exc.
  • print function. In python2, print is a keyword so you do this: print 'hello world'. In python3, it’s a function so you write it this way: print('hello world')
  • The strict separation of bytes and string types. Required me to specify that one subprocess function should return string instead of bytes to me

When I’ve worked on porting libraries that needed to maintain some form of compat between python2 (older versions… no nice shiny python-2.7 for you!) and python3 these concerns were harder to address as there needed to be two versions of the code (usually, maintained via automatic build-time invocation of 2to3). With this application/script, throwing out python2 compatibility was possible so switching over was just a matter of getting an error when the code executed and switching the syntax over.

This script also didn’t use any modules that had either not ported, been dropped, or been restructured in the switch from python2 to python3. Unlike my day job where urllib’s restructuring would affect many of the things that we’ve written and lack of ported third-party libraries would prevent even more things from being ported, this script (and many other of my simple-home-use scripts) didn’t require any changes due to library changes.

Verdict? Within these constraints, porting to python3 was as painless as porting between some python2.x releases has been. I don’t see any reason I won’t use python3 for new programming tasks like this. I’ll probably port other existing scripts as I need to enhance them.

Account System 0.8.11 Release

We’ve just deployed a new Fedora Account System to production. This release just pulls a few new features that didn’t quite make the 0.8.10 release:

  • Ian Cole (icole) Added a feature to allow for email address to be used instead of login name for logging in. Because of the way we do authentication, this means that email addresses can also be used on the other applications on as well.
  • Pierre-Yves Chibon (pingou) Implemented an audio captcha for people signing up for a new account. It generates a wav file that gets downloaded to your computer that you can listen to and then type in the proper answer to the captcha.
  • Adam M. Dutko (addutko) Standardized some of the errors that can be returned from our JSON API.
  • Our translation team pointed out a few areas where we weren’t loading translations correctly and I fixed them. Look forward to more complete translations in the future.

That’s it for this minor update.

/me goes to play with the audio captcha some more.

Kitchen 1.1.0 release

As mentioned last week a new kitchen release went out today. Since last week some small changes were made to the documentation and a few changes to make building kitchen easier were implemented but nothing has changed in the code. Here’s the text of the release announcement:

== Kitchen 1.1.0 has been released ==

Kitchen is a python library that brings together small snippets of code that you might otherwise find yourself reimplementing via cut and paste. Each little bit is useful and important but they usually feel too small and too trivial to create a whole module just for that one little function. However, experience has shown that any code implemented by copying will inevitably be shown to have bugs. And when you fix those bugs, you’ll wish you had created the module so you could fix the bug in one place rather than two (or five.. or ten…). Kitchen aims to be that one place.

Kitchen currently has code for easily setting up gettext so it won’t throw UnicodeErrors in corner cases, compatibility modules for different python2 stdlib versions (2.4, 2.5, 2.7), a little bit of iterators, and a whole lot of code for unicode-byte string conversion. In addition to the code, kitchen contains documentation that explains some of the common problems that arise when dealing with unicode in python2 and how to fix them through changes in coding practices and/or making use of functions from kitchen.

The 1.1.0 release enhances the gettext portion of kitchen. The major enhancements are:

  • get_translation_object can now be used as a drop in replacement for the stdlib’s gettext.translations() function.
  • If get_translation_object finds multiple message catalogs for the domain, it will setup the additional catalogs as fallbacks in case the message isn’t found in the first one.
  • The gettext and lgettext functions were reworked so that they guarantee that the string they return is both a byte str (this was present in previous kitchen releases) and is a valid sequence of bytes in the selected output_charset. This should prevent tracebacks if your code decodes and reencodes a value returned from the gettext and lgettext family of functions.
  • Several fixes to the way fallback message catalogs interacted with input and output charsets.

For the complete set of changes, see the NEWS file.

New kitchen release coming soon

[EDIT]For those who are curious, kitchen is a python module for miscellaneous code snippets. Things that people end up reimplementing via cut and paste because they seem to be too small to write a module for but are so useful that they need them in many places. Currently, it has code for i18n, compatibility modules for different python2 stdlib versions, a little bit of iterators, and a whole lot of code for unicode-byte string conversions.

Over the recent vacation I put the finishing (code) touches on a new kitchen release. I’ve scheduled the release of this code for next week on January 10, 2012. This is mainly since I just added the kitchen module on and I’d like to see if any translations show up before next week. If anyone finds any bugs in the code on python-2.3.1 through python-2.7.x, please bring them up on the mailing list, on (I hang out in #fedora-admin and #fedora-python), or in the kitchen bug tracker so that I can address them before the release date.

The beta code is available from at:

or from the bzr repository:

  bzr branch bzr://

The major changes are in the kitchen.i18n module. Previously, kitchen.i18n.*Translations objects guaranteed that they would return byte str when requested (via gettext(), ngettext(), lgettext(), and lngettext() methods) and unicode strings when requested (via ugettext() and ungettext()). The new code makes the additional guarantee that byte str‘s that are returned are valid in the requested output charset.

Here’s an example of the old behaviour vs new behaviour:

   >>> from kitchen.i18n import get_translation_object
   >>> translations = get_translation_object('kitchen')
   >>> b_ = translations.lgettext
   >>> translations.set_output_charset('utf-8')
   >>> translations.input_charset = 'latin-1'
   >>> # This would be: 'Café does not exist in the message catalog'
   >>> print repr(b_('Caf\xe9 does not exist in the message catalog'))
   # Old behaviour =>
   'Caf\xe9 does not exist in the message catalog'
   # New behaviour =>
   'Caf\xc3\xa9 does not exist in the message catalog'

   # Example 2: with wrong input_charset =>
   >>> translations.input_charset = 'utf-8'
   >>> print repr(b_('Caf\xe9 does not exist in the message catalog'))
   # New behaviour yields valid utf-8 bytes even when input_charset is wrong =>
   'Caf\xef\xbf\xbd does not exist in the message catalog'

Notice that this is not a magical panacea. The second example, shows that if input_encoding does not match the byte encoding of the strings that are given, the output string will be mangled (replacement characters or garbage characters). However, all the bytes in the output string will be valid in the chosen encoding so you won’t have to worry about exceptions if you attempt to transform the string again.

The other major change is that the kitchen.i18n.get_translation_object() function has been rewritten to be a drop in replacement for the stdlib’s gettext.translations(). The behaviour changes from that include the code now attempting to discover translations in every message catalog that it finds in the paths given to it. Additionally, those code changes lead to bugs in the *Translations classes fallback code being discovered and squashed.

See the NEWS file for other changes.

Brought to you by a cast of thousands (well, tens, at least)

The past few weeks I’ve been coordinating a new release of the Fedora Account System(FAS). Since FAS is something used within Fedora but not a whole lot of other places, development is usually driven by a relatively small handful of people: Ricky Zhou, Mike Mcgrath, and I. This release saw a large number of other contributors which has been very good as the three of us have been increasingly pulled into other projects so our time for FAS has steadily decreased.

  • Adam M. Dutko fixed several long standing bugs and feature requests
  • Luis Bazán updated several pieces of the UI
  • Sijis Aviles switched us from signing the CLA to the new FPCA
  • Pierre-Yves Chibon created a new captcha to replace the universally hated one that we were employing
  • Jun Chen added a means to clear a user’s ssh key
  • Nick Bebout started the work of removing copyright phrase-ology that we no longer want to use (“All rights reserved”) and tracking down which people needed to agree that we could switch licenses from GPLv2-only to GPLv2-or-later
  • Jim Lieb contributed code to make handling of languages easier and made FAS more configurable for use in other sites.
  • and for the first time in several releases we coordinated our release with the Fedora Translation Team on transifex so that the translations they contributed could go out with the first release instead of when a subsequent bugfix was released.

So let’s take a brief tour of some of these new features.

More Translations

Although we’ve been using transifex to manage translations for FAS for a while now, I hadn’t really understood how to leverage the full power of the Fedora Translation Team to get translations.  Thanks to some prodding by pingou, I got in touch with the translation team this time around and arranged for a string freeze before release during which they worked hard to translate FAS into their native languages. Thanks to transifex, I can show you this nice graph of their hard work:

Top translations: fas » faspot Full graph of translation stats

Clearing SSH Keys

When Fedora Infrastructure recently made the decision to invalidate public ssh keys because we had no way to tell which users might have hosted their ssh private keys on other projects servers which had been attacked and infiltrated, one of the options was for a user who didn’t actually need to use ssh to simply remove their ssh. Unfortunately, the web interface didn’t include the ability to do that so user’s who wanted to go this route had to contact one of the admins and have them remove it for them manually. Thanks to Jun Chen, users can now perform this step for themselves:
ssh clear key button

New Captcha!

There have always been many times more accounts in FAS than there were active contributors to Fedora. In itself, this wasn’t a problem. However, at some point, spammers started signing their bots up for Fedora accounts as they found that with that, they could write to the Fedora Wiki. To combat this, we added a captcha to the signup process. However, we quickly found that the captcha we added was too hard. Many people came to us to complain that they could not answer the captcha successfully. Thanks to pingou, we have a new captcha which displays a simple math equation in a much less distorted image. Writing the correct answer to the equation is all you need to do.
New captcha

These are just some of the more user visible changes. If you’re interested in the more behind the scenes changes (SELinux fixes from ricky, password strength checking, and more), check out the changes in FAS’s git repository.

Best Lightning Talk

At about 8:30 into this video, you’ll see a great lightning talk: PyCon 2011: Friday Afternoon Lightning Talks
It struck me on several levels.  It was told by an excellent straight man.  It had a great story.  It was gently deprecating.   In short it was very entertaining.
But beyond that, it also highlighted one of the core philosophies of open source that sometimes gets lost in mailing list threads about user base and popularity.  Open source is powered by people wanting to scratch their own itches.  Having a popular product is fun but people will work on something that only has a small amount of users as long as it is a good base for them to do what they want.

Need more Memory

For those installing the Fedora 15 Alpha into a VM, just a quick note — virt-manager currently defaults to 512MB of RAM for its VMs.  This isn’t enough RAM to boot the Alpha installer.

[11:37:59] <wwoods> F15 will need at least 640MB
[11:38:02] <wwoods> maybe 768
[11:38:42] <wwoods> I have a fix for that in the works but it’s kind of invasive and may not be ready ’til F16

Symptoms of trying to boot with too little memory may include a kernel oops when installing the rootfs.  Hope this helps people avoid head scratching later :-).

kitchen 0.2.4 released

I realize I didn’t announce 0.2.3 so here’s the NEWS entries for both of 0.2.3 and 0.2.4:


  • Have easy_gettext_setup() return lgettext functions instead of gettext
    functions when use_unicode=False
  • Correct docstring for kitchen.text.converters.exception_to_bytes() — we’re
    transforming into a byte str, not into unicode.
  • Correct some examples in the unicode frustrations documentation
  • Correct some cross-references in the documentation


  • Expose MAXFD, list2cmdline(), and mswindows in kitchen.pycompat27.subprocess.
    These are undocumented, and not in upstream’s __all__ but google (and bug
    reports against kitchen) show that some people are using them. Note that
    upstream is leaning towards these being private so they may be deprecated in
    the python3 subprocess.

So what do these changes mean for you? Hopefully it’ll just be bugfixes for everyone. The subprocess changes in 0.2.3 make more of the subprocess interface public because some code uses those functions and variables. People using them are advised to stop using them as this upstream bug report shows that the python maintainers don’t intend them to be public and will be deprecating them in the future. Since I had to dig into the code to look into this, I’ll also note that if your code is using list2cmdline() it it’s likely that it’s buggy in corner cases. From thesubprocess documentation: “list2cmdline() is designed for applications using the same rules as the MS C runtime.” That means that it’s not intended for dealing with Unix shells or even the MS-DOS command prompt. It’s only intended for the MS C runtime itself.

The 0.2.4 changes to easy_gettext_setup() changes behaviour so there is a potential to break code although I still classify it as a bugfix. easy_gettext_setup() is intended to return the gettext functions needed to translate an application. Since python has both byte str and unicode string types that can be used, there are gettext functions that return one or the other of those. easy_gettext_setup() takes a parameter, use_unicode to know whether to return a set of functions that works with byte str or a set of functions that work with unicode strings. There’s only one set of functions that return unicode so when unicode is requested the code returns the ugettext() and ungettext() functions as expected. When byte str is requested, however, things are a little messier as there’s two sets of function to choose from: gettext()/ngettext() or lgettext()/lngettext().

Prior to 0.2.4, easy_gettext_setup() returned gettext() and ngettext(). The gettext functions do return byte strings. However, the byte strings they return are in the encoding that was saved in the message catalogs on the filesystem. So, if the translators used utf-8 to encode their strings, you’d get utf-8 output; if they used latin-1, you’d get latin-1 output and so forth. This works fine as long as you’re using the same encoding as the translators were. However, when the translator uses a different encoding than you, you get mojibake.

In 0.2.4, we’ve switched to returning the lgettext functions to address this. lgettext and lngettext take the byte strings and the encoding information from the message catalog that the translator provided and use that to re-encode the strings in the desired encoding. That way if you have a locale setting of ja_JP.EUC_JP you get text encoded in EUC_JP and if you have a locale setting of ja_JP.UTF8 your text is encoded in UTF8.

Results from a program before and after updating the kitchen.i18n.easy_gettext_setup() function to use lgettext. In both terminals, the terminal is set to display characters using the EUC_JP encoding. The terminal on the right displays mojibake because the earlier version of easy_gettext_setup() uses the gettext() function which returns the characters in utf8 (the encoding that the translator used). The terminal on the right displays correctly because lgettext reencodes the strings as EUC_JP.

kitchen 0.2.2 released

Kitchen is a python module of small, useful snippets of code. It has functions to help with internationalizing applications, working with unicode and byte strings, iterators, and a whole bunch more.

0.2.2 is the first release that we’ve marked as a beta. The plan is to have a few weeks for people to try this out and report any bugs. If no bugs are reported we’ll release 1.0 soon afterwards. With that out the door, we’ll spend some time working on addon modules for a while — getting new features prototyped in separate submodules before merging them into a later kitchen 1.x (or 2.x) release.