Saturday, September 27, 2008

Tokyo Street Cats

Today, I went for a stroll through the streets of Kitano and Kitakarasuyama.


大きな地図で見る

Meeting lots of cats and having happy moments with them.

20080927_0107_1 20080927_0111_1 20080927_0115_1

Hide and seek? :-)

20080927_0112_1 20080927_0118_1

Friday, September 26, 2008

Python version check

Just use sys.hexversion instead of the string equivalent (sys.version, sys.version_info, ...). It's flexible and fast.

>>> import sys
>>> sys.hexversion
33882608
>>> hex(sys.hexversion)
'0x20501f0'
>>> if sys.hexversion >= 0x2050100:
...   print "Python 2.5.1 or higher"
... 
Python 2.5.1 or higher

For example, the explicit relative imports is introduced in Python 2.5, you can check this function as:

HAS_RELATIVE_IMPORTS = (sys.hexversion >= 0x2050000)

NOTE: sys.hexversion is available since 1.5.2. It's not worth to support older versions.

Wednesday, September 24, 2008

pylint: disable/enable message for a block or statement

One of my favorite things about pylint is a feature that allows to disable/enable message for a block or statement.

For instance, consider the function below:

def scan_code(co, module):
    assert co and module
    if DEBUG: print co.co_filename
    ...

The function scan_code has so many debug prints. For performance reason, however, they are if DEBUG: print statements. Now pylint would report so many messages (C: means convention, for programming standard violation).

% pylint scan_code
...
C:107:scan_code: More than one statement on a single line
C:110:scan_code: More than one statement on a single line
C:114:scan_code: More than one statement on a single line
C:117:scan_code: More than one statement on a single line
C:123:scan_code: More than one statement on a single line

You can disable these messages for scan_code function. # pylint: disable-msg=... style comment can be used everywhere in the source code and affects a block or statement.


# pylint: disable-msg=C0321
def scan_code(co, module):
    assert co and module
    if DEBUG: print co.co_filename
    ...

See Also

Tuesday, September 23, 2008

The Power of Python's Generator expressions and Tuple pack/unpack

Python's Generator expressions and Tuple pack/unpack is more powerful than I thought.

for k, v in d.iteritems():
  if v > 123:
    yield k, v

is equivalent to:

return (item for item in d.iteritems() if item[1] > 123)

Some simple generators can be coded using Generator expressions, and Tuple pack/unpack is an easy way to return multiple values.

% python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {'apple': 256, 'hoge': 123, 'orange': 555}
>>> 
>>> def fn_yield():
...   for k, v in d.iteritems():
...     if v > 123:
...       yield k, v
... 
>>> def fn_generator():
...   return (item for item in d.iteritems() if item[1] > 123)
... 
>>> for k, v in fn_yield():
...   print k, v
... 
orange 555
apple 256
>>> for k, v in fn_generator():
...   print k, v
... 
orange 555
apple 256

Monday, September 22, 2008

Do you know Universal Newline Support in Python?

Do you know Universal Newline Support in Python? To be honest, I didn't know that. The PEP 278 describes in detail:

In a Python with universal newline support open() the mode parameter can also be "U", meaning "open for input as a text file with universal newline interpretation". Mode "rU" is also allowed, for symmetry with "rb". Mode "U" cannot be combined with other mode flags such as "+". Any line ending in the input file will be seen as a '\n' in Python, so little other code has to change to handle universal newlines.

Conversion of newlines happens in all calls that read data: read(), readline(), readlines(), etc.

Here is an example:

% printf 'Hello, World!\r\n' > /tmp/hello.txt
% cat /tmp/hello.txt 
Hello, World!
% python 
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> open('/tmp/hello.txt').read()
'Hello, World!\r\n'
>>> open('/tmp/hello.txt', 'U').read()
'Hello, World!\n'

If Python was built with the --with-universal-newlines option to configure (the default), File objects have newlines attribute, so testing whether the current Python has universal newline support can be done with:

if hasattr(sys.__stdout__, "newlines"):
    print "universal line endings"

Sunday, September 21, 2008

How to compile Python source file with or without optimization

py_compile and compileall module provides functions to generate a byte-code file from a source file. You can not, however, enable or disable byte code optimization at runtime.

The byte code optimization depends the built-in variable __debug__ in the current interpreter, and assignments to __debug__ are illegal. Python 2.2 (or later) is strict about that.

% python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> __debug__
True
>>> __debug__ = False
  File "<stdin>", line 1
SyntaxError: can not assign to __debug__

So you can't enable/disable optimization flag without running another interpreter (using '-O' switch).

Example: Using os.spawnv to run and compile files with or without optimization

Monday, September 15, 2008

assertNone/assertNotNone

Why Python unittest module lacks assertNone/assertNotNone? I think this lack would cause problems as API misuse. For example:

obj = factory.make_object()
self.assert_(obj) # must not be None (?)

I intended to say "factory.make_object must not return None", but It can fail even False and such an empty object (0, "", [], ...).

I should have written like:

obj = factory.make_object()
self.assert_(obj is not None) # must not be None!

Repeating that code, however, is so boring, a lot of the visual noise, and error-prone. Writing assertNone/assertNotNone:

class TestCase(unittest.TestCase):
    """Custom TestCase class"""

    def failUnlessNone(self, expr, msg=None):
        """Fail the test unless the expression is None."""
        if expr is not None: raise self.failureException, msg

    def failIfNone(self, expr, msg=None):
        """Fail the test if the expression is None."""
        if expr is None: raise self.failureException, msg

    # Synonyms for assertion methods
    assertNone = failUnlessNone
    assertNotNone = failIfNone

pylint: -r/--reports option doesn't work

The following pylint command still outputs reports:

% pylint --reports=no module

versions and environment:

% uname -a
Darwin macbook3.local 9.4.0 Darwin Kernel Version 9.4.0: Mon Jun  9 19:30:53 PDT 2008; root:xnu-1228.5.20~1/RELEASE_I386 i386
% python --version
Python 2.5.1
% pylint --version
No config file found, using default configuration
pylint 0.15.0,
astng 0.17.3, common 0.35.0
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
[GCC 4.0.1 (Apple Inc. build 5465)]

on Mac OS X 10.5.4.

I gave a quick look at the pylint source code. Removing optparse's default option fixes this problem (see below), but I don't know why.

--- pylint_orig/lint.py 2008-09-14 18:49:35.000000000 +0900
+++ /Library/Python/2.5/site-packages/pylint-0.15.0-py2.5.egg/pylint/lint.py 2008-09-14 18:50:07.000000000 +0900
@@ -184,7 +184,7 @@
 Reports (if any) will be written in a file name "pylint_global.[txt|html]".'}),
                
                ('reports',
-                {'default': 1, 'type' : 'yn', 'metavar' : '',
+                {'type' : 'yn', 'metavar' : '',
                  'short': 'r',
                  'group': 'Reports',
                  'help' : 'Tells wether to display a full report or only the\