The Case for Peewee: Small, Hackable and Fun


SQLAlchemy is one of those tools that is so powerful and so well-established that it's hard to imagine a time when it didn't exist. Mike Bayer, the project's primary author, after what I'm sure was a lot of real-world experience, hit on the right amount of abstraction and API that pleases both die-hard DBA types as well as more casual users.

So why would anyone use peewee?

Solving different problems

I often mentally compare SQLAlchemy with the relational database Postgresql. Postgresql comes with everything you could want in an RDBMS, and is even adding features more commonly found in popular non-relational databases, such as the new jsonb functions and HStore. Postgresql is the go-to relational database in the communities I follow (like proggit and haternews). And likewise, SQLAlchemy is the database toolkit loved most by serious Python developers.

I also think SQLite is a fantastic database. I mention SQLite because, on the surface, it seems comparable to Postgresql. After all, they're both relational databases.

I think the similarity ends there, though. Postgresql is intended to solve a vastly different set of problems than SQLite. D. Richard Hipp, the author of SQLite, gave an awesome keynote at PGCon this year which outlines some of the differences between the libraries. Postgresql's goal is to be the world's most advanced open-source database, while SQLite's goal is to replace fopen(). To put it another way, Postgresql is like a swiss army knife, with lots of neat tools for various purposes, while SQLite is like a scalpel. SQLite has a much more limited scope, and my feeling is that it's primary strength lies in that focus.

SQLAlchemy is, in my mind, the swiss army knife of Python ORMs. I bet SQLAlchemy can handle any query or relational structure you want to throw at it. Additionally, the unit of work and identity-mapper patterns provide great performance and solve some problems you might encounter when using an active-record ORM. Being built from the bottom-up, SQLAlchemy also provides nice APIs no matter how near or far you want to be from SQL.

Peewee, as it's name indicates, is much (much) smaller in scope. The project's goal is to provide composable, expressive, and predictable APIs for executing SQL queries and working with tabular data. Peewee's APIs are very close to their SQL counterparts, and there is only a thin layer of abstraction between the ORM code you write and the generated SQL. I think peewee is attractive to developers who already know SQL and want an unobstrusive, Pythonic way to use a relational database. It is my hope that peewee's simplicity is also it's strength.

Architecturally, peewee is also different from SQLAlchemy. peewee follows the active-record pattern which is also used by the Django ORM. Transactions are managed explicitly and by default each connection runs in autocommit mode. Like Django and SQLAlchemy, peewee uses declarative model classes with a variety of field types exposed as class attributes. Unlike Django, peewee uses operator overloading to create SQL expressions, e.g. User.username == 'huey'.

Simplicity encourages hacking


My father-in-law enjoys working on cars, and among other feats of engineering, he's rebuilt a sweet 1960's mustang (painted Springtime Yellow). On several occasions I've heard him say how the complexity of modern vehicles makes it almost impossible for amateur mechanics to work on them. My brother has worked in the automotive field for about 6 years and he shares this sentiment. His hobby is to turn old Toyota trucks into monster rock crawlers, and one of the main reasons he prefers older model-years is because they're just easier to work on. My step-father always preferred 2-stroke dirtbikes for the same reason.

Peewee tries to be, for developers, what a 1960's mustang is for my father-in-law: aesthetically pleasing, a pleasure to use, and most importantly, something you can easily hack on. If you need to look under-the-hood (sorry, horrible pun) at the source code, there is only a single file to read. I've also worked very hard to create useful documentation for peewee, and at the time I'm writing this, the PDF version of the docs is over 120 pages long!

The simplicity of peewee has proved itself useful time after time as I've added new features and debugged problems. Even as the code-base has doubled in size since the 2.0 release two years ago (which was a complete rewrite), the APIs have, if anything, become more simple. The call stack is never more than a few calls deep, and the objects interact in predictable ways. radon, a tool that measures the cyclomatic complexity of Python code, gave peewee an "A", with an average complexity of 2.43. Here is the list of functions whose complexity is C or worse (where "C" means moderate - slightly complex block):

$ radon cc --total-average -nc
    C 3349:0 BaseModel - D
    M 3353:4 BaseModel.__new__ - D
    M 2004:4 AggregateQueryResultWrapper.iterate - D
    M 1490:4 QueryCompiler.generate_select - C
    C 1796:0 ExtQueryResultWrapper - C
    M 1797:4 ExtQueryResultWrapper.initialize - C
    M 1579:4 QueryCompiler.generate_insert - C
    M 2182:4 Query.filter - C

474 blocks (classes, functions, methods) analyzed.
Average complexity: A (2.42616033755)

I then used radon once more to measure the lines of source code in each project. Peewee and the playhouse extension modules weighed in at just over 6,000 SLOC, which is hopefully small enough to allow folks to dive in and come away with an understanding of the library in an hour or two.

Have fun out there

More than anything, I want peewee to be fun to use. Because it's so easy to get up and running with peewee, I've found that I'm much more eager to write little scripts or micro-services to solve day-to-day problems. I've written a note-taking app that I couldn't function without, a personalized news feed, a lastpass-style password manager, and many more fun little apps. Peewee also is great for doing data analysis -- I've thrown server logs into peewee, used peewee to explore CSV files, and other projects. In short, I really enjoy using peewee and hope you will, too.

Competition encourages innovation

Even if you never use peewee, it's my hope that the Python community overall benefits from diversity in the selection of ORM libraries. A little competition forces everyone to step their game up, and I also think it's good to force the end-users to think critically about the choice they make in third-party libraries. Pony ORM is another ORM to come out recently. Pony uses bytecode decompilation to turn Python generator expressions into SQL, an approach that I think is as brilliant as it is crazy! If you're interested in checking out a comparison of some various Python ORMs, this project contains the same "Hello world" Flask app written using some of the most popular database libraries.

Thanks for taking the time to read this post, please feel free to leave a comment or contact me.

Most importantly, happy hacking!

Comments (0)

Commenting has been closed, but please feel free to contact me