Have you tried just generating the docstrings at decoration time and
applying them? By the sound of it, they won't change after that, and
the only reason to run it later is performance... but have you
actually measured a performance hit resulting from that?
I did. On my laptop (Intel i7-4700MQ), it takes about 4-12 milliseconds to parse and reformat a single condition lambda function of a contract. This quickly adds up to a couple of seconds if you have thousands of condition functions to parse. This might not be a problem for a limited code base, but I imagine that it could get inefficient very quickly as soon as the contract usage would spread to the dependencies as well. Not dead-slow inefficient, but inefficient enough to consider whether the automatic doc generation is worth it.