Esempio n. 1
0
def _makeTypeTable(classes, enums, properties):
    # Used for constructing k.keywords
    # Each argument is of format [[name, code], ...]
    typebycode = _typebycode.copy()
    typebyname = _typebyname.copy()
    # TO DO: testing indicates that where name+code clashes occur, classes have highest priority, followed by properties, with enums last; currently this code gives higher priority to enums:
    for klass, table in [
        (AEType, properties), (AEEnum, enums), (AEType, classes)
    ]:  # note: packing properties as AEProp causes problems when the same name is used for both a class and a property, and the property's definition masks the class's one (e.g. Finder's 'file'); if an AEProp is passed where an AEType is expected, it can cause an error as it's not what the receiving app expects. (Whereas they may be more tolerant of an AEType being passed where an AEProp is expected.) Also, note that AppleScript always seems to pack property names as typeType, so we should be ok following its lead here.
        for i, (name, code) in enumerate(table):
            # TO DO: decide where best to apply AE keyword escaping, language keyword escaping
            # TO DO: make sure same collision avoidance is done in help terminology (i.e. need to centralise all this stuff in a single osaterminology module)
            # If an application-defined name overlaps an existing type name but has a different code, append '_' to avoid collision:
            if _typebyname.has_key(name) and _typebyname[name].code != code:
                name += '_'
            typebycode[code] = Keyword(
                name
            )  # to handle synonyms, if same code appears more than once then use name from last definition in list
            name, code = table[-i - 1]
            if _typebyname.has_key(name) and _typebyname[name].code != code:
                name += '_'
            typebyname[name] = klass(
                code
            )  # to handle synonyms, if same name appears more than once then use code from first definition in list
    return typebycode, typebyname
Esempio n. 2
0
def _makeTypeTable(classes, enums, properties):
    # Used for constructing k.keywords
    # Each parameter is of format [[name, code], ...]
    typebycode = _typebycode.copy()
    typebyname = _typebyname.copy()
    for klass, table in [
        (AEType, classes), (AEEnum, enums), (AEType, properties)
    ]:  # note: packing properties as AEProp causes problems when the same name is used for both a class and a property, and the property's definition masks the class's one (e.g. Finder's 'file'); if an AEProp is passed where an AEType is expected, it can cause an error as it's not what the receiving app expects. (Whereas they may be more tolerant of an AEType being passed where an AEProp is expected.) Also, note that AppleScript always seems to pack property names as typeType, so we should be ok following its lead here.
        for name, code in table:
            # TO DO: decide where best to apply AE keyword escaping, language keyword escaping
            # TO DO: make sure same collision avoidance is done in help terminology (i.e. need to centralise all this stuff in a single osaterminology module)
            # If an application-defined name overlaps an existing type name but has a different code, append '_' to avoid collision:
            if _typebyname.has_key(name) and _typebyname[name].code != code:
                name += '_'
            typebycode[code] = Keyword(name)
            typebyname[name] = klass(code)
    return typebycode, typebyname
Esempio n. 3
0
def _maketypetable(classes, enums, properties):
    # Used for constructing k.keywords
    # Each argument is of format [[name, code], ...]
    typebycode = _defaulttypebycode.copy()
    typebyname = _defaulttypebyname.copy()
    # note: testing indicates that where name+code clashes occur, classes have highest priority, followed by properties, with enums last (prior to 0.19.0 this code gave higher priority to enums):
    for klass, table in [
        (AEEnum, enums), (AEType, properties), (AEType, classes)
    ]:  # note: packing properties as AEProp causes problems when the same name is used for both a class and a property, and the property's definition masks the class's one (e.g. Finder's 'file'); if an AEProp is passed where an AEType is expected, it can cause an error as it's not what the receiving app expects. (Whereas they may be more tolerant of an AEType being passed where an AEProp is expected.) Also, note that AppleScript always seems to pack property names as typeType, so we should be ok following its lead here.
        for i, (name, code) in enumerate(table):
            # If an application-defined name overlaps an existing type name but has a different code, append '_' to avoid collision:
            if _defaulttypecodebyname.get(name, code) != code:
                name += '_'
            typebycode[code] = Keyword(
                name
            )  # to handle synonyms, if same code appears more than once then use name from last definition in list
            name, code = table[-i - 1]
            if _defaulttypecodebyname.get(name, code) != code:
                name += '_'
            typebyname[name] = klass(
                code
            )  # to handle synonyms, if same name appears more than once then use code from first definition in list
    return typebycode, typebyname
Esempio n. 4
0
######################################################################
# Default terminology tables for converting between human-readable identifiers and Apple event codes; used by all apps.
# Includes default entries for Required Suite, get/set and miscellaneous other commands; application may override some or all of these definitions.

# Type tables; used to translate constants
# e.g. k.document <-> AEType('docu')
# e.g. k.ask <-> AEEnum('ask ')

_typebyname = {}  # used to encode class and enumerator keywords
_typebycode = {
}  # used to decode class (typeType) and enumerator (typeEnum) descriptors

for _, enumerators in appscripttypedefs.enumerations:
    for name, code in enumerators:
        _typebyname[name] = AEEnum(code)
        _typebycode[code] = Keyword(name)
for defs in [
        appscripttypedefs.alltypes, appscripttypedefs.commontypes,
        appscripttypedefs.properties
]:
    for name, code in defs:
        _typebyname[name] = AEType(code)
        _typebycode[code] = Keyword(name)

# Reference tables; used to translate references and commands
# e.g. app(...).documents.text <-> app.elements('docu').property('ctxt')
# e.g. app(...).quit(saving=k.ask) <-> Application(...).event('aevtquit', {'savo': AEEnum('ask ')})

_defaultcommands = {
    # 'run', 'open', 'print' and 'quit' are Required Suite commands so should always be available.
    'run': (kCommand, ('aevtoapp', {})),
Esempio n. 5
0
# Default terminology tables for converting between human-readable identifiers and Apple event codes; used by all apps.
# Includes default entries for Required Suite, get/set and miscellaneous other commands; application may override some or all of these definitions.

# Type tables; used to translate constants
# e.g. k.document <-> AEType('docu')
# e.g. k.ask <-> AEEnum('ask ')

_defaulttypebyname = {}  # used to encode class and enumerator keywords
_defaulttypebycode = {
}  # used to decode class (typeType) and enumerator (typeEnum) descriptors
_defaulttypecodebyname = {}  # used to check for name collisions

for _, enumerators in defaultterminology.enumerations:
    for name, code in enumerators:
        _defaulttypebyname[name] = AEEnum(code)
        _defaulttypebycode[code] = Keyword(name)
        _defaulttypecodebyname[name] = code
for defs in [defaultterminology.types, defaultterminology.properties]:
    for name, code in defs:
        _defaulttypebyname[name] = AEType(code)
        _defaulttypebycode[code] = Keyword(name)
        _defaulttypecodebyname[name] = code

# Reference tables; used to translate references and commands
# e.g. app(...).documents.text <-> app.elements('docu').property('ctxt')
# e.g. app(...).quit(saving=k.ask) <-> Application(...).event('aevtquit', {'savo': AEEnum('ask ')})

_defaultreferencebycode = {}  # used to decode property and element specifiers
_defaultreferencebyname = {
}  # used to encode property and element specifiers and Apple events
_defaultcommandcodebyname = {}  # used to check for name collisions
Esempio n. 6
0
class AppData(aem.Codecs):
    """Provides application-specific:
		- aem.Application instance
		- name-code terminology translation tables
		- pack/unpack methods
		- help system
	"""

    #######
    # constants, etc.

    keyAECompOperator = aem.AEType(kae.keyAECompOperator)
    keyAEObject1 = aem.AEType(kae.keyAEObject1)
    keyAEObject2 = aem.AEType(kae.keyAEObject2)

    kAppscriptTypeCompDescriptorOperators = {
        kae.kAEGreaterThan: 'AS__gt__',
        kae.kAEGreaterThanEquals: 'AS__ge__',
        kae.kAEEquals: 'AS__eq__',
        kae.kAELessThan: 'AS__lt__',
        kae.kAELessThanEquals: 'AS__le__',
        kae.kAEBeginsWith: 'beginswith',
        kae.kAEEndsWith: 'endswith',
        kae.kAEContains: 'contains'
    }

    kClassKeyword = Keyword('class_')
    kClassType = aem.AEType('pcls')

    kHelpAgentBundleID = 'net.sourceforge.appscript.asdictionary'

    #######
    # initialiser

    def __init__(self, aemapplicationclass, constructor, identifier, terms):
        """
			aemapplicationclass : class -- aem.Application or equivalent
			constructor : str -- indicates how to construct the aem.Application instance ('path', 'pid', 'url', 'aemapp', 'current')
			identifier : any -- value identifying the target application (its type is dependent on constructor parameter)
			terms : bool | module | tuple
		"""
        # initialise codecs
        aem.Codecs.__init__(self)
        self.decoders.update({
            kae.typeType:
            self.unpackkeyword,
            kae.typeEnumerated:
            self.unpackkeyword,
            kae.typeProperty:
            self.unpackkeyword,
            kae.typeObjectSpecifier:
            self.unpackreference,
            kae.typeInsertionLoc:
            self.unpackreference,
            # AEAddressDesc types
            kae.typeApplicationBundleID:
            self.unpackapplicationbyid,
            kae.typeApplicationURL:
            self.unpackapplicationbyurl,
            kae.typeApplSignature:
            self.unpackapplicationbysignature,
            kae.typeKernelProcessID:
            self.unpackapplicationbypid,
            kae.typeMachPort:
            self.unpackapplicationbydesc,
            kae.typeProcessSerialNumber:
            self.unpackapplicationbydesc,
        })
        # store parameters for later use
        self._aemapplicationclass = aemapplicationclass
        self.constructor, self.identifier = constructor, identifier
        self._relaunchmode = 'limited'
        self._terms = terms
        self._helpagent = None

    #######

    # Terminology-aware pack/unpack functions.
    # These replace the default aem pack/unpack functions, which don't understand appscript Keyword and Reference objects.

    def packdict(self, val):
        # Pack dictionary whose keys are strings (e.g. 'foo'), Keywords (e.g. k.name) or AETypes (e.g. AEType('pnam').
        record = newrecord()
        if self.kClassKeyword in val or self.kClassType in val:
            # if hash contains a 'class' property containing a class name, coerce the AEDesc to that class
            newval = val.copy()
            if self.kClassKeyword in newval:
                value = newval.pop(self.kClassKeyword)
            else:
                value = newval.pop(self.kClassType)
            if isinstance(
                    value, Keyword
            ):  # get the corresponding AEType (assuming there is one)
                value = self.typebyname().get(value.name, value)
            if isinstance(value,
                          aem.AEType):  # coerce the record to the desired type
                record = record.coerce(value.code)
                val = newval
        usrf = None
        for key, value in val.items():
            if isinstance(key, Keyword):
                try:
                    keyCode = self.typebyname()[key.AS_name].code
                except KeyError:
                    raise KeyError("Unknown Keyword: k.%s" % key.AS_name)
                record.setparam(keyCode, self.pack(value))
            elif isinstance(
                    key, aem.AETypeBase
            ):  # AEType/AEProp (AEType is normally used in practice)
                record.setparam(key.code, self.pack(value))
            else:  # user-defined key (normally a string)
                if not usrf:
                    usrf = newlist()
                usrf.setitem(0, self.pack(key))
                usrf.setitem(0, self.pack(value))
        if usrf:
            record.setparam('usrf', usrf)
        return record

    def unpackaerecord(self, desc):
        # Unpack typeAERecord,  converting record keys to Keyword objects (not AETypes) where possible.
        dct = {}
        for i in range(desc.count()):
            key, value = desc.getitem(i + 1, kae.typeWildCard)
            if key == 'usrf':
                lst = self.unpack(value)
                for i in range(0, len(lst), 2):
                    dct[lst[i]] = lst[i + 1]
            elif key in self.typebycode():
                dct[self.typebycode()[key]] = self.unpack(value)
            else:
                dct[aem.AEType(key)] = self.unpack(value)
        return dct

    ##

    def unpackkeyword(self, desc):
        # Unpack typeType, typeEnum, typeProperty; replaces default aem decoders to convert types, enums, etc.
        # to Keyword objects instead of AETypes, AEEnums, etc.
        aemValue = _lowlevelcodecs.unpack(desc)
        return self.typebycode().get(aemValue.code, aemValue)

    def unpackreference(self, desc):
        return Reference(self, _lowlevelcodecs.unpack(desc))

    def unpackcompdescriptor(self, desc):
        # need to do some typechecking when unpacking 'contains' comparisons, so have to override the low-level unpacker
        rec = self.unpack(desc.coerce(kae.typeAERecord))
        operator = self.kAppscriptTypeCompDescriptorOperators[rec[
            self.keyAECompOperator].code]
        op1 = rec[self.keyAEObject1]
        op2 = rec[self.keyAEObject2]
        if operator == 'contains':
            if isinstance(
                    op1,
                    Reference) and op1.AS_aemreference.AEM_root() == aem.its:
                return op1.contains(op2)
            elif isinstance(
                    op2,
                    Reference) and op2.AS_aemreference.AEM_root() == aem.its:
                return op2.isin(op1)
            else:
                return _lowlevelcodecs.unpack(desc)
        else:
            return getattr(op1, operator)(op2)

    ##

    def unpackapplicationbyid(self, desc):
        return app(id=desc.data)

    def unpackapplicationbyurl(self, desc):
        if desc.data.startswith(
                'file'
        ):  # workaround for converting AEAddressDescs containing file:// URLs to application paths, since AEAddressDescs containing file URLs don't seem to work correctly
            return app(mactypes.File.makewithurl(desc.data).path)
        else:  # presumably contains an eppc:// URL
            return app(url=desc.data)

    def unpackapplicationbysignature(self, desc):
        return app(creator=struct.pack('>I', struct.unpack('I', desc.data)[0]))

    def unpackapplicationbypid(self, desc):
        return app(pid=struct.unpack('I', desc.data)[0])

    def unpackapplicationbydesc(self, desc):
        return app(aemapp=aem.Application(desc=desc))

    #######

    def connect(self):
        """Initialises application target and terminology lookup tables.
		
		Called automatically the first time clients retrieve target, typebycode, typebyname,
		referencebycode, referencebyname; clients should not need to call it themselves.
		"""
        # initialise target (by default an aem.Application instance)
        if self.constructor == 'aemapp':
            t = self._target = self.identifier
        elif self.constructor == 'current':
            t = self._target = self._aemapplicationclass()
        else:
            t = self._target = self._aemapplicationclass(
                **{self.constructor: self.identifier})
        # initialise translation tables
        if self._terms == True:  # obtain terminology from application
            self._terms = terminology.tablesforapp(t)
        elif self._terms == False:  # use built-in terminology only (e.g. use this when running AppleScript applets)
            self._terms = terminology.defaulttables
        elif not isinstance(self._terms,
                            tuple):  # use user-supplied terminology module
            self._terms = terminology.tablesformodule(self._terms)
        d1, d2, d3, d4 = self._typebycode, self._typebyname, \
          self._referencebycode, self._referencebyname = self._terms
        self.target = lambda: t
        self.typebycode = lambda: d1
        self.typebyname = lambda: d2
        self.referencebycode = lambda: d3
        self.referencebyname = lambda: d4

    def target(self):
        self.connect()
        return self._target

    def typebycode(self):
        self.connect()
        return self._typebycode

    def typebyname(self):
        self.connect()
        return self._typebyname

    def referencebycode(self):
        self.connect()
        return self._referencebycode

    def referencebyname(self):
        self.connect()
        return self._referencebyname

    ##

    def pack(self, data):
        if isinstance(data, GenericReference):
            data = data.AS_resolve(Reference, self)
        if isinstance(data, Reference):
            data = data.AS_aemreference
        elif isinstance(data, Keyword):
            try:
                data = self.typebyname()[data.AS_name]
            except KeyError:
                raise KeyError("Unknown Keyword: k.%s" % data.AS_name)
        return aem.Codecs.pack(self, data)

    # Relaunch mode

    def _setrelaunchmode(self, mode):
        if mode not in ['never', 'limited', 'always']:
            raise ValueError('Unknown relaunch mode: %r' % mode)
        self._relaunchmode = mode

    relaunchmode = property(lambda self: self._relaunchmode, _setrelaunchmode)

    # Help system

    def _write(self, s):
        if isinstance(s, unicode):
            s = s.encode('utf8')
        print >> sys.stderr, s

    def _inithelpagent(self):
        try:
            apppath = aem.findapp.byid(self.kHelpAgentBundleID)
            asdictionaryisrunning = aem.Application.processexistsforpath(
                apppath)
            self._helpagent = aem.Application(apppath)
            if not asdictionaryisrunning:
                # tell System Events hide ASDictionary after it's launched (kludgy, but does the job)
                aem.Application(
                    aem.findapp.byid('com.apple.systemevents')).event(
                        'coresetd', {
                            '----':
                            aem.app.elements('prcs').byname(
                                'ASDictionary').property('pvis'),
                            'data':
                            False
                        }).send()
                self._helpagent.event(
                    'AppSHelp', {
                        'Cons': self.constructor,
                        'Iden': self.identifier,
                        'Styl': 'py-appscript',
                        'Flag': '-h',
                        'aRef': None,
                        'CNam': ''
                    }).send()
            return True
        except aem.findapp.ApplicationNotFoundError:
            self._write(
                "No help available: ASDictionary application not found.")
        except aem.CantLaunchApplicationError:
            self._write(
                "No help available: can't launch ASDictionary application.")
        return False

    def _displayhelp(self, flags, ref):
        if isinstance(ref, Command):
            commandname = ref.AS_name
            ref = ref.AS_aemreference
        else:
            commandname = ''
        try:
            self._write(
                self._helpagent.event(
                    'AppSHelp', {
                        'Cons': self.constructor,
                        'Iden': self.identifier,
                        'Styl': 'py-appscript',
                        'Flag': flags,
                        'aRef': self.pack(ref),
                        'CNam': commandname
                    }).send())
            return None
        except aem.EventError, e:
            return e
Esempio n. 7
0
            print_exc()
        return ref


######################################################################
# Considering/ignoring constants


def _packuint32(n):  # used to pack csig attributes
    return newdesc(kae.typeUInt32, struct.pack('I', n))


# 'csig' attribute flags (see ASRegistry.h; note: there's no option for 'numeric strings' in 10.4)

_ignoreenums = [
    (Keyword('case'), kae.kAECaseConsiderMask, kae.kAECaseIgnoreMask),
    (Keyword('diacriticals'), kae.kAEDiacriticConsiderMask,
     kae.kAEDiacriticIgnoreMask),
    (Keyword('whitespace'), kae.kAEWhiteSpaceConsiderMask,
     kae.kAEWhiteSpaceIgnoreMask),
    (Keyword('hyphens'), kae.kAEHyphensConsiderMask, kae.kAEHyphensIgnoreMask),
    (Keyword('expansion'), kae.kAEExpansionConsiderMask,
     kae.kAEExpansionIgnoreMask),
    (Keyword('punctuation'), kae.kAEPunctuationConsiderMask,
     kae.kAEPunctuationIgnoreMask),
]

# default cons, csig attributes

_defaultconsiderations = _lowlevelcodecs.pack([aem.AEEnum(kae.kAECase)])
_defaultconsidsandignores = _packuint32(kae.kAECaseIgnoreMask)
Esempio n. 8
0
class AppData(aem.Codecs):
	"""Provides application-specific:
		- aem.Application instance
		- name-code terminology translation tables
		- pack/unpack methods
		- help system
	"""
	
	#######
	# constants, etc.
	
	keyAECompOperator = aem.AEType(kae.keyAECompOperator)
	keyAEObject1 = aem.AEType(kae.keyAEObject1)
	keyAEObject2 = aem.AEType(kae.keyAEObject2)

	kAppscriptTypeCompDescriptorOperators = {
			kae. kAEGreaterThan: 'AS__gt__',
			kae.kAEGreaterThanEquals: 'AS__ge__',
			kae.kAEEquals: 'AS__eq__',
			kae.kAELessThan: 'AS__lt__',
			kae.kAELessThanEquals: 'AS__le__',
			kae.kAEBeginsWith: 'beginswith',
			kae.kAEEndsWith: 'endswith',
			kae.kAEContains: 'contains'
	}
	
	kClassKeyword = Keyword('class_')
	kClassType = aem.AEType('pcls')
	
	kHelpAgentBundleID = 'net.sourceforge.appscript.asdictionary'
	
	
	#######
	# initialiser
	
	def __init__(self, aemapplicationclass, constructor, identifier, terms, aemconstructoroptions={}):
		"""
			aemapplicationclass : class -- aem.Application or equivalent
			constructor : str -- indicates how to construct the aem.Application instance ('path', 'pid', 'url', 'aemapp', 'current')
			identifier : any -- value identifying the target application (its type is dependent on constructor parameter)
			terms : bool | module | tuple -- if True, retrieve terminology from target application dynamically; 
					if false, use only default terminology; if static glue module or tuple, use terminology from that
			aemconstructoroptions -- any additional keyword arguments to pass to aemapplicationclass constructor
					(e.g. newinstance, hide)
		"""
		# initialise codecs
		aem.Codecs.__init__(self)
		self.decoders.update({
				kae.typeType: self.unpackkeyword,
				kae.typeEnumerated: self.unpackkeyword,
				kae.typeProperty: self.unpackkeyword,
				kae.typeObjectSpecifier: self.unpackreference,
				kae.typeInsertionLoc: self.unpackreference,
				# AEAddressDesc types
				kae.typeApplicationBundleID: self.unpackapplicationbyid,
				kae.typeApplicationURL: self.unpackapplicationbyurl,
				kae.typeApplSignature: self.unpackapplicationbysignature,
				kae.typeKernelProcessID: self.unpackapplicationbypid,
				kae.typeMachPort: self.unpackapplicationbydesc,
				kae.typeProcessSerialNumber: self.unpackapplicationbydesc,
		})
		# store parameters for later use
		self._aemapplicationclass = aemapplicationclass
		self.constructor, self.identifier = constructor, identifier
		self.aemconstructoroptions = aemconstructoroptions
		self._relaunchmode = 'limited'
		self._terms = terms
		self._helpagent = None
		self._isconnected = False
	
	
	#######
	
	# Terminology-aware pack/unpack functions.
	# These replace the default aem pack/unpack functions, which don't understand appscript Keyword and Reference objects.
	
	def packdict(self, val):
		# Pack dictionary whose keys are strings (e.g. 'foo'), Keywords (e.g. k.name) or AETypes (e.g. AEType('pnam').
		record = newrecord()
		if self.kClassKeyword in val or self.kClassType in val:
			# if hash contains a 'class' property containing a class name, coerce the AEDesc to that class
			newval = val.copy()
			if self.kClassKeyword in newval:
				value = newval.pop(self.kClassKeyword)
			else:
				value = newval.pop(self.kClassType)
			if isinstance(value, Keyword): # get the corresponding AEType (assuming there is one)
				value = self.typebyname().get(value.name, value)
			if isinstance(value, aem.AEType): # coerce the record to the desired type
				record = record.coerce(value.code)
				val = newval
		usrf = None
		for key, value in val.items():
			if isinstance(key, Keyword):
				try:
					keyCode = self.typebyname()[key.AS_name].code
				except KeyError:
					raise ValueError("Unknown Keyword: k.%s" % key.AS_name)
				record.setparam(keyCode, self.pack(value))
			elif isinstance(key, aem.AETypeBase): # AEType/AEProp (AEType is normally used in practice)
				record.setparam(key.code, self.pack(value))
			else: # user-defined key (normally a string)
				if not usrf:
					usrf = newlist()
				usrf.setitem(0, self.pack(key))
				usrf.setitem(0, self.pack(value))
		if usrf:
			record.setparam('usrf', usrf)
		return record
	
	
	def unpackaerecord(self, desc):
		# Unpack typeAERecord,  converting record keys to Keyword objects (not AETypes) where possible.
		dct = {}
		for i in range(desc.count()):
			key, value = desc.getitem(i + 1, kae.typeWildCard)
			if key == 'usrf':
				lst = self.unpack(value)
				for i in range(0, len(lst), 2):
					dct[lst[i]] = lst[i+1]
			elif key in self.typebycode():
				dct[self.typebycode()[key]] = self.unpack(value)
			else:
				dct[aem.AEType(key)] = self.unpack(value)
		return dct

	##
	
	def unpackkeyword(self, desc):
		# Unpack typeType, typeEnum, typeProperty; replaces default aem decoders to convert types, enums, etc.
		# to Keyword objects instead of AETypes, AEEnums, etc.
		aemValue = _lowlevelcodecs.unpack(desc)
		return self.typebycode().get(aemValue.code, aemValue)
	
	
	def unpackreference(self, desc):
		return Reference(self, _lowlevelcodecs.unpack(desc))
	
	
	def unpackcompdescriptor(self, desc):
		# need to do some typechecking when unpacking 'contains' comparisons, so have to override the low-level unpacker
		rec = self.unpack(desc.coerce(kae.typeAERecord))
		operator = self.kAppscriptTypeCompDescriptorOperators[rec[self.keyAECompOperator].code]
		op1 = rec[self.keyAEObject1]
		op2 = rec[self.keyAEObject2]
		if operator == 'contains':
			if isinstance(op1, Reference) and op1.AS_aemreference.AEM_root() == aem.its:
				return op1.contains(op2)
			elif isinstance(op2, Reference) and op2.AS_aemreference.AEM_root() == aem.its:
				return op2.isin(op1)
			else:
				return _lowlevelcodecs.unpack(desc)
		else:
			return getattr(op1, operator)(op2)
	
	##
	
	def unpackapplicationbyid(self, desc):
		return app(id=desc.data)
	
	def unpackapplicationbyurl(self, desc):
		if desc.data.startswith('file'): # workaround for converting AEAddressDescs containing file:// URLs to application paths, since AEAddressDescs containing file URLs don't seem to work correctly
			return app(mactypes.File.makewithurl(desc.data).path)
		else: # presumably contains an eppc:// URL
			return app(url=desc.data)
	
	def unpackapplicationbysignature(self, desc):
		return app(creator=struct.pack('>I', struct.unpack('I', desc.data)[0]))
	
	def unpackapplicationbypid(self, desc):
		return app(pid=struct.unpack('I', desc.data)[0])
	
	def unpackapplicationbydesc(self, desc):
		return app(aemapp=aem.Application(desc=desc))

	#######
	
	isconnected = property(lambda self: self._isconnected)
	
	def connect(self):
		"""Initialises application target and terminology lookup tables.
		
		Called automatically the first time clients retrieve target, typebycode, typebyname,
		referencebycode, referencebyname; clients should not need to call it themselves.
		"""
		# initialise target (by default an aem.Application instance)
		if self.constructor == 'aemapp':
			t = self._target = self.identifier
		elif self.constructor == 'current':
			t = self._target = self._aemapplicationclass()
		else:
			kargs = {self.constructor: self.identifier}
			kargs.update(self.aemconstructoroptions)
			t = self._target = self._aemapplicationclass(**kargs)
		# initialise translation tables
		if self._terms == True: # obtain terminology from application
			self._terms = terminology.tablesforapp(t)
		elif self._terms == False: # use built-in terminology only (e.g. use this when running AppleScript applets)
			self._terms = terminology.defaulttables
		elif not isinstance(self._terms, tuple): # use user-supplied terminology module
			self._terms = terminology.tablesformodule(self._terms)
		d1, d2, d3, d4 = self._typebycode, self._typebyname, \
				self._referencebycode, self._referencebyname = self._terms
		self.target = lambda: t
		self.typebycode = lambda: d1
		self.typebyname = lambda: d2
		self.referencebycode = lambda: d3
		self.referencebyname = lambda: d4
		self._isconnected = True
	
	def target(self):
		self.connect()
		return self._target
	
	def typebycode(self):
		self.connect()
		return self._typebycode
	
	def typebyname(self):
		self.connect()
		return self._typebyname
	
	def referencebycode(self):
		self.connect()
		return self._referencebycode
	
	def referencebyname(self):
		self.connect()
		return self._referencebyname
		
	_kYes = Keyword('yes')
	_kNo = Keyword('no')
	_kAsk = Keyword('ask')
	
	def permissiontoautomate(self, code=kae.typeWildCard*2):
		try:
			self.target().permissiontoautomate(code[:4], code[4:], True)
		except MacOSError, e:
			if e.args[0] == -1744: # errAEEventWouldRequireUserConsent
				return self._kAsk # unknown (i.e. user has yet to allow/forbid access)
			elif e.args[0] == -1743: # errAEEventNotPermitted (broken in 10.14.x; see <rdar://44049802>)
				return self._kNo
			else: # e.g. -600 (process not found)
				raise
		except NotImplementedError: # always True if OS version < 10.14
			pass
Esempio n. 9
0
            flags, ref
        )  # call real help. Note that help system is responsible for providing a return value (usually the same reference it was called upon, but it may modify this).


######################################################################
# Considering/ignoring constants


def _packUInt64(n):  # used to pack csig attributes
    return AECreateDesc(kAE.typeUInt32, struct.pack('L', n))


# 'csig' attribute flags (see ASRegistry.h; note: there's no option for 'numeric strings' in 10.4)

_ignoreEnums = [
    (Keyword('case'), aem.k.CaseConsider, aem.k.CaseIgnore),
    (Keyword('diacriticals'), aem.k.DiacriticConsider, aem.k.DiacriticIgnore),
    (Keyword('whitespace'), aem.k.WhiteSpaceConsider, aem.k.WhiteSpaceIgnore),
    (Keyword('hyphens'), aem.k.HyphensConsider, aem.k.HyphensIgnore),
    (Keyword('expansion'), aem.k.ExpansionConsider, aem.k.ExpansionIgnore),
    (Keyword('punctuation'), aem.k.PunctuationConsider,
     aem.k.PunctuationIgnore),
]

# default cons, csig attributes

_defaultConsiderations = _lowLevelCodecs.pack([aem.AEType('case')])
_defaultConsidsAndIgnores = _packUInt64(aem.k.CaseIgnore)

######################################################################
# Base class for references and commands