Practical Maya Programming with Python is Published


My book, Practical Maya Programming with Python has been finally published! Please check it out and tell me what you think. I hope you will find it sufficiently-but-not-overly opinionated :) It is about as personal as a technical book can get, being distilled from years of mentoring many technical artists and programmers, which is a very intimate experience. It also grows from my belief and observation that becoming a better programmer will, due to all sorts of indirect benefits, help make you a better person.

If you are using Python as a scripting language in a larger application- a game engine, productivity software, 3D software, even a monolithic codebase that no longer feels like Python- there’s a lot of relevant material here about turning those environments into more standard and traditional Python development environments, which give you better tools and velocity. The Maya knowledge required is minimal for much of the book. Wrapping a procedural undo system with context managers or decorators is universal. A short quote from the Preface:

This book is not a reference. It is not a cookbook, and it is not a comprehensive guide to Maya’s Python API. It is a book that will teach you how to write better Python code for use inside of Maya. It will unearth interesting ways of using Maya and Python to create amazing things that wouldn’t be possible otherwise. While there is plenty of code in this book that I encourage you to copy and adapt, this book is not about providing recipes. It is a book to teach skills and enable.

Finally, to those who pre-ordered, I’m truly sorry for all the delays. They’re unacceptable. I hope you’ll buy and enjoy the book anyway. At least I now have a real-world education on the perils of working with the wrong publisher, and won’t be making that same mistake again.

Thanks and happy reading!
Rob Galanakis

No Comments

goless 0.7 released, with Python3 support and bug fixes


goless version 0.7.0 is out on PyPI. goless facilitates writing Go language style concurrent programs in Python, including functionality for channels, select, and goroutines.

I forgot to blog about 0.6 at the start of July, which brought Python 3.3 and 3.4 support to goless (#17). I will support pypy3 as soon as Travis supports it.

Version 0.7 includes:
- A “fix” for a gevent problem on Windows (socket must be imported!). #28
- Errors in the case of a deadlock will be more informative. For example, if the last greenlet/tasklet tries to do a blocking send or recv, a DeadlockError will be raised, instead of the underlying error being raised. #25
- goless now has a small exception hierarchy instead of exposing the underlying errors.
- Better PyPy stackless support. #29
- can be called with (case1, case2, case3), etc., in addition to a list of cases (ie, ([case1, case2, case3])). #22

Thanks to Michael Az for several contributions to this release.

Happy concurrent programming!

No Comments

goless now on PyPI


goless is now available on the Python Package Index: . You can do pip install goless and get Go-like primitives to use in Python, that runs atop gevent, PyPy, or Stackless Python. You can write code like:

channel = goless.chan()

def goroutine():
    while True:
        value = channel.recv()
        channel.send(value ** 2)

for i in xrange(2, 5):
    squared = channel.recv()
    print('%s squared is %s' % (i, squared))

# Output:
# 2 squared is 4
# 3 squared is 9
# 4 squared is 16

I’ve also ported the goless benchmarks to Go, for some basic comparisons to using goless on various Python runtimes (PyPy, CPython) and backends (gevent, stackless):

Thanks to Rui Carmo we have more extensive examples of how to use goless (but if you’ve done or read any Go, it should be relatively straightforward). Check them out in the examples folder:

And just a compatibility note (which is covered in the docs, and explained in the exception you get if you try to use goless without stackless or gevent available): goless works out of the box with PyPy (using in its stdlib) and Stackless Python. It works seamlessly with gevent and CPython 2.7. It works with PyPy and gevent if you use the tip of gevent and PyPy 2.2+. It will support Python 3 as soon as gevent does.

Thanks and if you use goless, I’m eager to hear your feedback!

No Comments

goless Benchmarks


I benchmarked how goless performs under different backends (goless is a library that provides a Go-like concurrency model for Python, on top of stackless, PyPy, or gevent). Here are the results, also available on the goless readthedocs page:

Platform Backend   Benchmark      Time
======== ========= ============== =======
PyPy     stackless chan_async     0.08400
CPython  stackless chan_async     0.18000
PyPy     gevent    chan_async     0.46800
CPython  gevent    chan_async     1.32000
~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~~~~~~ ~~~~~~~
PyPy     stackless chan_buff      0.08000
CPython  stackless chan_buff      0.18000
PyPy     gevent    chan_buff      1.02000
CPython  gevent    chan_buff      1.26000
~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~~~~~~ ~~~~~~~
PyPy     stackless chan_sync      0.04400
CPython  stackless chan_sync      0.18000
PyPy     gevent    chan_sync      0.44800
CPython  gevent    chan_sync      1.26000
~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~~~~~~ ~~~~~~~
PyPy     stackless select         0.06000
CPython  stackless select         0.38000
PyPy     gevent    select         0.60400
CPython  gevent    select         1.94000
~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~~~~~~ ~~~~~~~
PyPy     stackless select_default 0.00800
PyPy     gevent    select_default 0.01200
CPython  stackless select_default 0.19000
CPython  gevent    select_default 0.25000

The trends are that PyPy with its built-in stackless support is fastest, then Stackless Python (2-5x), then PyPy with gevent (5-10x), and finally CPython with gevent (15-30x).

Remember that these are benchmarks of goless itself; goless performance characteristics may be different in real applications. For example, if you have lots of C extensions, CPython/stackless may pull ahead due to stack switching.

If you’re using goless for anything, I’d love to get some benchmarks, and find out how it’s working, so please comment below, or create a GitHub issue.

Disclaimers: It’s possible that goless is inefficiently using gevent, but the backend-specific code is so simple I doubt it (see goless/goless/ These benchmarks are all done against Python 2.7. Also I am no benchmark master (especially with PyPy) so there may be problems, look over goless/ for benchmark code. These were done mostly for curiosity.

No Comments

Deploying a C# app through pip


“If we bundle up this C# application inside of a Python package archive we can deploy it through our internal CheeseShop server with very little work.”

That sentence got me a lot of WTF’s and resulted in one of the worst abuses of any system I’ve ever committed.

We had a C# service that would run locally and provide an HTTP REST API for huge amounts of data in our database that was difficult to work with.* However, we had no good way to deploy a C# application, but we needed to get this out to users so people could start building tools against it.
I refused to deploy it by running it out of source control. That is how we used to do stuff and it caused endless problems. I also refused bottlenecks like IT deploying new versions through Software Center.

So in an afternoon, I wrote up a Python package for building the C# app, packaging it into a source distribution, and uploading to our Cheese Shop. The package also had functions for starting the packaged C# executable from the installed distribution. The package then became a requirement like anything else and was added to a requirements.txt file that was installed via pip.

What I initially thought was an unsightly hack ended up being perfect for our needs. In fact it caused us to eliminate a number of excessive future plans we had around distribution. I certainly wouldn’t recommend this “technique” for anything more than early internal distribution, but that’s what we needed and that’s what it did so effectively.

Getting something up and running early was extremely useful. It’s important to walk the line between the “we need to do several weeks of work before you see any result” and “I can hack something together we’re going to regret later,” especially for infrastructure and platform work. If code is well-written, tested, documented, and explained, you shouldn’t have qualms about it going into (internal) production. If the hackiness is hidden from clients, it can be easily removed when the time comes.

* Reworking the data was not an option. Creating this service would have allowed us to eventually rework the data, by providing an abstraction, though.


Adjustable standing desks should be mandatory


At CCP’s Iceland office, everyone’s desk is able to adjust into a sitting or standing position. I don’t know who decided this perk. It must have been a huge expense. Adjustable sit/stand desks are already expensive in the USA, and in Iceland I’m sure they were three to five times more expensive. Until recently I thought it was required by law! This is quite an investment for each worker, but in my opinion, well worth it for a wide variety of reasons, from health to programming. Why?

  • Lots of people want to try a standing desk but don’t want to be “that guy” who asks for an expensive piece of equipment but doesn’t use it. Having an adjustable desk by default removes barriers to entry.
  • Seeing people stand (and talk about how much better it is) becomes viral. I watched it catch on at work over a few years to where everyone in certain areas is doing it. This wouldn’t have been possible without everyone already having adjustable desks.
  • Standing for part of the day completely fixed my sciatica (lower back/hip/butt pain). It also apparently has lots of other health benefits.

Okay, but “health of your workers” is a pretty nebulous concept, and in America, a business’ job is to make money for shareholders, not, like, improve society! Why would Donald Sterling want to buy black employees adjustable desks in addition to cars and houses?

  • It helped me concentrate. I was able to work faster while standing. Standing is time for working. I don’t know if this is universal, but I certainly didn’t see many people playing games or getting lost in a “YouTube hole” (as a friend puts it) while standing.
  • Pair programming and over-the-shoulder reviews were incredibly more effective while standing, even with people of different heights. Standing, I could pair easily with pretty much anyone, from a good friend to an interviewee. I was able to mentor far more effectively since standing felt like such a more natural way to collaborate.
  • Even if you don’t like pair programming (have you tried pairing while standing?), being able to program and edit code collaboratively during a code review is, IMO, a requirement. Standing code reviews were more effective than sitting. More issues got uncovered and more knowledge was transferred.

How do I know all these things? Well, when I transferred to the Atlanta office, I no longer had an adjustable desk (or a sensible healthcare system, but that’s another matter). Suddenly, reviews with people I was very comfortable with and worked with previously felt rushed and unpleasant. They were done while leaning over (“when can I get my crotch out of this other person’s face“), or sitting together (“oh god we keep brushing knees“).

Pair programming, which is the foundation of the way I mentor (and learn), was basically ineffective. No one programs well at an angle to the monitor, and people mistype constantly if the keyboard is not in a natural spot. It’s difficult to share knowledge or equipment in such an awkward situation.

If you want a vibrant and dynamic engineering culture, standing desks are a must. I view them as fundamental to a programming team as decent workstations and SSDs.

Real studies about adjustable desks are difficult to find. This 538 analysis is promising: Otherwise, it is very easy to find endless anecdotes about the usefulness of adjustable desks. Start with the 538 article’s comments if you don’t know anyone!


Maya Python Binaries for Windows


I’ve put together a page to link and host all the various Python C extensions compiled for various flavors of Autodesk Maya on Windows:

This is due to Maya using newer VS compilers than Python 2.6/2.7, which uses VS2008. Much more info on the page.

I’ll try and keep this up to date. If you have anything to contribute, please post it somewhere and send me the link (or send the files to me, whatever).

No Comments

An Unfoolish Consistency: Introducing PEP8 to a legacy codebase


Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important.

The EVE source code, being initially developed before PEP8 existed, was based on Microsoft’s C++ style. Mostly this is manifested in UpperCamelCase function and method names, mixedCase parameter and variable names, and file headers and class/method delimiters. There was also a style guide that was probably larger than PEP8 (though included a bit more than basic style).

Today, most new code is PEP8 compliant. “What!?” I hear you say. “A foolish consistency is the hobgoblin of little minds!” I agree, and I’ll get back to that at the end. But first, what was involved in introducing PEP8?

The move started when I asked my team if anyone wanted to keep using the headers and delimiters. No one did. So we took out the headers and delimiters before we did any modifications to a file.

A while later, I asked all the programmers on the project if anyone felt strongly about keeping the existing style. No one did. So we started writing new packages with PEP8. The rationale was that our code was already calling code using lowercase_underscore in the stdlib, so it’d be no different for that same code to call a relatively independent, though still project-related, library.

Yet a while later, I started slipping some PEP8 code into modules or packages that weren’t PEP8. I was worried people would get upset. No one did.

And finally, in preparing some basic utility libraries for usage on other projects, I converted the function and method names to PEP8. This involved find-and-replace or CamelCase aliases. I bet you can guess who cared about these “superfluous” edits, or objected to the fact that parameter and variable names remained mixedCase? No one did.

Emerson’s quote “a foolish consistency is the hobgoblin of little minds” is often used as a reason to not change existing code to PEP8, or introduce it into a non-PEP8 codebase. But the quote means the opposite. Foolish consistency” is being unable to change your mind because it would contradict something you’ve believed or said. So PEP8 has it so right but so wrong: the foolish consistency is to keep things the way they are, even though we know what the right thing to do is.*

* I would recommend introducing PEP8 incrementally. I also suggest keeping things backwards compatible when it is more prudent, such as if the changes are expansive, or you do not control all the code. I also don’t suggest being a stylistic nitpicker when it comes to non-functional aspects such as line length. There may also be times to break the rules (a class that behaves like a function, or function that behaves like a class def). As always, good sense should be applied when considering any viewpoints on this blog.

No Comments

goless- Golang semantics in Python


The goless library provides Go programming language semantics built on top of Stackless Python or gevent.* Here is a Go example using channels and Select converted to goless:

c1 = goless.chan()
c2 = goless.chan()

def func1():

def func2():

for i in range(2):
    case, val =[goless.rcase(c1), goless.rcase(c2)])

While I am not usually a Go programmer, I am a big fan of its style and patterns. goless provides the familiarity and practicality of Python while better enabling the asynchronous/concurrent programming style of Go. Right now it includes:

  • Synchronous/unbuffered channels (send and recv block waiting for a receiver or sender).
  • Buffered channels (send blocks if buffer is full, recv blocks if buffer is empty).
  • Asynchronous channels (do not exist in Go. Send never blocks, recv blocks if buffer is empty).
  • The select function (like reflect.Select, since Python does not have anonymous blocks we could not replicate Go’s Select statement).
  • The go function (runs a function in a tasklet/greenlet).

goless is pretty well documented and tested, but please take a look or give it a try and tell us what you think here or on GitHub’s issues. I’m especially interested in adding more Go examples converted to use goless, or other Go features replicated to create better asynchronous programs.**

*. goless was written at the PyCon 2014 sprints by myself, Carlos Knippschild, and Simon Konig, with help from Kristjan Valur Jonsson and Andrew Francis (sorry the lack of accents here, I am on an unfamiliar computer). Carlos and myself were both laid off while at PyCon- if you have an interesting job opportunity for either of us, please send me an email:

**. We are close to getting PyPy support working through its implementation. There are some lingering issues in the tests (though the examples and other ‘happy path’ code works fine under PyPy). I’ll post again and bump the version when it’s working.


Global Glob


I am cleaning out my drafts and found this two year old post titled “Globals Glob” with no content. The story is worth telling so here we go.

There was a class the EVE client used to control how missiles behaved. We needed to start using it in our tools for authoring missiles with their effects and audio. The class and module was definitely only designed (I used the term loosely) to run with a full client, and not inside of our tools, which are vanilla Python with a handful of modules available.

My solution was the GlobalsGlob base class, which was just a bag of every singleton or piece of data used by the client that was unavailable to our tools. So instead of:


it’d be:


The ClientGlobalsGlob called the service, but FakeGlobalsGlob did nothing. The GlobalsGlob allowed us to use the missile code without having to rewrite it. A rewrite was out of the question, as it had just been rewritten, except using the same code. (sigh)

Unsurprisingly, GlobalsGlob was super-fragile. So we added a test to make sure the interface between the client and fake globs were the same, using the inspect module. This helped, but of course things kept breaking.

This all continued until the inevitable and total breakdown of the code. Trying to use the missile code in tools was abandoned (I think it was, I have no idea what state it’s in). This was okay though, as we weren’t using the missile tools much after those few months. GlobalsGlob served its purpose, but I will never be able to decide if it was a success or failure.