@superflea: vertex colors instead of weights is simple, in fact that was the first version I wrote but then I realized I cannot use a vertex color as a density map in a particle system. I uploaded that version to GitHub. You can use it vertex paint mode and there you can find it in the paint menu. It only uses the red channel.
About dividing by pi: the angle() member function returns a value in radians, so any angle between the normal and the z-axis will be between 0 and pi. However, I want those weights to be in the range [0,1] so that’s why I divide and then subtract from 1.
I intend to add options to control this mapping for precisely the reason you mention For now you could tweak the sourcecode to read something like below to make steep slope far less likely to receive grass (tweak the power of 2 to taste :-):
vertex_group.add([v.index], angle ** 2, ‘REPLACE’)