This is the second in a finite series of articles about the development of aeve.
...Continuing from where I left off:
aeve.util
I didn't quite finish this one out last time (I think I was tired). aeve.util is generic could-be-anywhere Python
code.
aeve.util.ShortBitmask
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 , 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
0
>>> erf.replyOptional
32768
>>> erf.singleItem
16384
>>> erf.enumerated
8192
>>> erf
40960 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
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') After:
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
|