Bob Ippolito (@etrepum) on Haskell, Python, Erlang, JavaScript, etc.

aeve-o-rama vol.2


This is the second in a finite series of articles about the development of aeve.

...Continuing from where I left off:


I didn't quite finish this one out last time (I think I was tired). aeve.util is generic could-be-anywhere Python code.


This is probably the least generally useful module in aeve.util, but the code is portable and it doesn't say Apple anywhere, so I figured this would be the right place for it, but it could or perhaps should be in aeve.terminology. The aete resource format (yes, that documentation is really from 1996) uses these 2-byte "flags" everywhere. In AEUserTermTypes.r [1], they're arrays of boolean pairs, and that's the representation I chose to use. ShortBitmask is an int subclass, with a metaclass that does the dirty work. It's not meant to be used directly, but to be again subclassed and provided with a __pairs__ member that enumerate the properties. None is a placeholder property for a reserved bit. Here's what it looks like in action:

>>> from aeve.util.ShortBitmask import ShortBitmask
>>> class EventReplyFlags(ShortBitmask):
...   __pairs__ = (
...     ('replyRequired', 'replyOptional'),
...     ('singleItem', 'listOfItems'),
...     ('notEnumerated', 'enumerated'),
...   )
>>> erf = EventReplyFlags(1 << 15 | 1 << 13)
>>> erf.replyRequired
>>> erf.replyOptional
>>> erf.singleItem
>>> erf.enumerated
>>> erf

I'm using the masks themselves instead of booleans for a reason, I forget what it is at the moment, but I certainly had one. In any case, it's equivalent to what it would be as a boolean and it's faster to just return the integer without the conversion (not that I care). This odd hack is only so I don't have to carry around a bunch of per-flag-type constants later on (in aeve.runtime and aeve.compiler). It does make it harder (but still possible) to create runtime types by hand, as they expect ShortBitmask subclasses and not ints (the same goes for NamedTuple vs. tuple). I'm willing to trade that "convenience" for readable code.


aeve.constants is probably one of the most and least useful parts of aeve. Basically what I did was take the AppleEvents constants from Python itself (bgen generated from the C header), converted it all over to aeve.util.Enumerations, and grouped it into classes that I could understand (for my reference, not used in code).

Before (these aren't marked as related.. they're mixed in with the other 958 lines of constants):

keyDirectObject = FOUR_CHAR_CODE('----')
keyErrorNumber = FOUR_CHAR_CODE('errn')
keyErrorString = FOUR_CHAR_CODE('errs')
keyProcessSerialNumber = FOUR_CHAR_CODE('psn ')
keyPreDispatch = FOUR_CHAR_CODE('phac')
keySelectProc = FOUR_CHAR_CODE('selh')
keyAERecorderCount = FOUR_CHAR_CODE('recr')
keyAEVersion = FOUR_CHAR_CODE('vers')


class AEEventParameterKeywords(FourCharCodeEnumeration):
    """Keywords for Apple event parameters"""
    keyDirectObject = FourCharCode('----')
    keyErrorNumber = FourCharCode('errn')
    keyErrorString = FourCharCode('errs')
    keyProcessSerialNumber = FourCharCode('psn ')
    keyPreDispatch = FourCharCode('phac')
    keySelectProc = FourCharCode('selh')
    keyAERecorderCount = FourCharCode('recr')
    keyAEVersion = FourCharCode('vers')

Yes, my code does needlessly use FourCharCode (since it will get turned into the mixed-in FourCharCode __baseclass__ anyway when the metaclass creates it). My excuse is that I was using regular expressions to do all this, and didn't feel a need to chop it out. I also compared the standard MacPython version (it used an older version of Universal Headers) with the OS X headers and I actually had to add in some missing OS X related constants, such as the typeApplicationBundleID, typeKernelProcessID, and typeMachPort addressing modes.

... to be continued

[1]See /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers/AEUserTermTypes.r
[2]See /System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/plat-mac/Carbon/