typecheck


As promised, a word on the newest typecheck derivative, type_algebra.

type_algebra is being spun off to hold things like Xor(), Not(), Any(), i.e., things that are more neat than they are useful. It also serves as a good, easy example of how to extend typecheck for one’s own ends.

With this in mind, a few other things are going in: first up, a Nothing() class to complement Any() — where as Any() approves everything, Nothing() approves, well, nothing.

I’m probably going to add smarter versions of And() and Or() classes with beefed up intelligence as to how to simplify certain types of type expressions. Again, things that are cooler/interesting than they are useful/practical.

While tarballs aren’t yet available (type_algebra will ship with typecheck 0.4.0), you can follow along at home via the WebSVN viewer.

typecheck has kinda been on the back burner for…oh…the last few months, let’s say. In my defense, I’ve been a bit busy, primarily with the “travelling around Europe” thing. However, I’ve also been hard at work at a PEP to add function annotations to Python 3.0 — a project I hope to have more news on shortly.

Today, however, typecheck took a good-size surge forward. The main thrust of the 40+ commits were to bring typecheck more into line with the style of function annotations that Python 3.0 will have. To this end:

  • In past releases of typecheck, it’s been required that every parameter have a type annotation. In 0.4, this will change; type annotations, now done exclusively through keyword arguments, will be completely optional. To wit, with typecheck < 0.4, this:

    @accepts(Number, Number)
    def foo(a, b):
        ...

    becomes

    @accepts(a=Number, b=Number)
    def foo(a, b):
        ...

  • Since types are now optional, there’s no need for things like Self(), which will go away

  • The dual spellings of types for *vargs and **kwargs are going bye-bye. Whereas in typecheck < 0.4 these were equivalent

    @accepts(vargs=Number)
    def sum(*vargs):
        ....
    
    @accepts(vargs=[Number])
    def sum(*vargs):
        ....

    In typecheck 0.4, the latter signature will expect that each argument to sum is a list of Numbers.

In addition, the Xor(), Not() and Any() annotation classes are going away; they’re being spun off into a separate type_algebra package that will be shipped in typecheck’s contrib directory. More on that later, too.

In order to let people play with the latest changes to typecheck as soon as they’re available, some new goodies have been added to the site:

  1. The development version of the website is now available for perusal. Why would you want this? Because the development version contains the docs for all the spiffy new features that will be coming out in the next release.

    The devel version of the site (yes, the whole site) can be found at http://oakwinter.com/code/typecheck/dev/.

  2. In addition, the latest SVN revision (for trunk/) is now available in handy tarball form. The URL for the tarball will stay consistent, even when the tarball’s contents change. To figure out which revision you have, check the included REVISION file.

The latest change that you might want to play with is the new assert_type function. This is intended for in-code type checks, which can be a good deal more efficient than the traditional decorator-based checks. See the function’s docs for more details and examples.

I’d like to give a proud-father-ly salute to Maxime Bourget’s typecheck frontend. Combining typecheck with the TPG parser generator, the frontend allows you to specify a function’s types using Haskell-like syntax in the callable’s docstring. To wit:

>>> from ize.typechecker import *
>>> @tize
... def f(x):
...     ':: int -> int'
...     return x+10
...
>>>

…which defines the function f as taking an int and returning an int.

All praise and suggestions go to Maxime Bourget (maxime dot bourget at gmail period com).

People are doing things with typecheck! Huzzah!

Most recently on my radar, Marc Rijken has contributed a package that combines typecheck with Zope interfaces (like Roles in Perl 6). I’ve imported his code into typecheck's SVN repository, meaning that it will be shipped with the next release of the package.

For those interested in trying it out now, the code is available from the SVN repository (svn://oakwinter.com//var/svn/typecheck) under trunk/contrib.

First, the typecheck project — both the website and Subversion repository — have been moved to oakwinter.com. The new URL is http://oakwinter.com/code/typecheck.

Second, the website has been given a thorough scrubbing. The documentation has been greatly cleaned up and has been broken into separate tutorial and reference manual sections.

Last but not least, typecheck release 0.3.4 has been shipped off to SourceForge, PyPI and the project’s own website. This new release features the concept of typeclasses, a way of grouping classes and types based on functionality. See the documenation for details.

This will probably be the last release in the 0.3.x series. Next up will be the 0.4 release; this version will shed a lot of antiquated backwards compatibility mechanisms (for values of “antiquated” approaching “version 0.1.6″) and a general streamlining of the package’s functionality.

As part of the push to get an initial release of svnmock out the door, I’ve spent the last two weeks or so working on a website for the project. The biggest part of this effort has been writing documentation, particularly a tutorial, to explain this silly package.

By and large, the documentation has been fairly easy to write. I’m pretty good at, and enjoy, the very precise, technical style needed to write exacting specifications. I also look at spec writing as an opportunity to double-check the test suite; for every claim about how a given piece of code operates, I add a footnote pointing to the area of the test suite that verifies that claim. True, this makes things take longer than they otherwise would, but I’ve found several untested bits of code this way.

The tutorial section, on the other hand, has been torture. Whereas spec writing involves merely throwing down everything I know about the code in the most lawyer-like language I can summon, crafting a tutorial requires writing about the project as if I knew nothing about it and were exploring it for the first time. It can get frustrating, trying to distill an entire software package into simple, little words.

A similar effort has been underway for typecheck, as well. I’m pushing to have the project ready for publication on comp.lang.python by 0.4, our next minor-version release. We’ve recently brought David Wheeler on board, and he’s given me some good insights as to things we can do better.

One of the big problems he’s pointed out so far is the package’s documentation. It sucks, and you’ll get no argument from me about that. The docs have long consisted of a single, pages-long document that skims the package’s functionality. This format is left over from Iain Lowe’s initial effort, and while it may have worked in the past, the current version of the package is too large, too wide-ranging, to fit in a single page.

My current effort has involved breaking the current document into a sectioned-off tutorial and reference manual. As a result, it’s much better organised now, with a hint of “flow” and a dash of “coherence”. Also, I’m spending a lot of time working on more realisitic examples; as it is, a lot of the demos use the int and float types, which makes for simple examples, but they’re not very realistic.

I’m hoping to get the initial draft out the door some time today, then open the floor for comments and revisions. Mmm…open source.

The typecheck project grew out of a desire to gain more safety in my python programs. Whereas the majority of the python community seems to be in love with (or at least, “ok with”) the idea of duck-typing, duck-typing has always struck me as a post-fact rationalisation of the decision to make python a weakly-typed language. In less fancy language: I hate duck-typing so much, I’m willing to spend a few months developing a way to get away from it.

So, what is the typecheck package? At its most primative, it provides a way to make sure the arguments to your functions, methods and generators (and their return values) are of the expected types. Going further, it offers a wealth of extensibility, allowing — and expecting — programmers to push it much further than simple “is argument ‘a’ an integer?” typechecking. Beyond this rudimentary mode of operation, the typecheck package ships with the following tools:

  • Utility classes allowing the programmer to build up more complex “types” from boolean expressions. Though the And(), Not() and Or() classes can of course be used with all built-in and user-defined types, they can also be nested within one another to produce all other boolean operators.

  • Other utility classes exist to enforce duck-typed constraints. For example, IsCallable() asserts that the object can be invoked like a function, and IsIterable() ensures that you’ll be able to utilise the object in for loops. A HasAttr() class is provided, allowing assertions that the object has certain, specified attributes.

  • The typecheck package borrows the concept of “type variables” from languages like Haskell. Type variables allow you to say, “I don’t care what type parameter ‘a’ is, but parameters ‘c’ and ‘d’ need to be of that same type, as does the function’s return value.”

Beyond these standard tools, care has been taken to allow, for example, user-defined container classes to hook into the typechecker, providing type safety for the most exotic of classes. For simple iterator container classes, mixins exist to provide drop-in typechecking capabilities.

The project’s website is: http://oakwinter.com/code/typecheck/. There, you’ll find links to more complete documentation, the project’s Subversion archive, and source and Python Egg distributions.

My involvement - the original typecheck project was developed by Iain Lowe. In Fall 2005, I started working on my own typechecker to address certain limitations of Iain’s code, though also intending to keep full, interface-level backwards compatibility with what he had done. In November 2005, I felt my codebase was complete enough for a 0.1 release and so contacted Iain about merging our projects. He agreed, and my code became the core of the combined typechecker. I’m currently leading the coding and documentation work on the project.