Is there a way to determine if a contact exists in a specific account? For example, my iPad syncs with both an Exchange server and iCloud, and I am trying to clean up some of the duplicates between both accounts. However, when I look at the contacts returned by Python, I can’t find a way to distinguish which account a specific contact came from. Is there a way to do this that I am missing?
Forum Archive
Distinguish contacts between two accounts
@tonytx05, for some reason (I am guessing historically poor API design that they are now a bit stuck with), Apple has made the link between contacts and accounts difficult to determine, even with the ObjectiveC API. See e.g. here.
@tonytx05 could you test this little quick and dirty script, and give me some feedback.
I can't really test because I only have iCloud contacts...
from objc_util import *
import contacts
# ObjectiveC contacts
objc_contacts = {}
CNContactStore = ObjCClass('CNContactStore').alloc().init()
CNContact = ObjCClass('CNContact')
Containers = CNContactStore.containersMatchingPredicate_error_(None,None)
for Container in Containers:
id = Container.identifier()
predicate = CNContact.predicateForContactsInContainerWithIdentifier_(id)
# keys not exactly like in Apple doc
# found a sample here https://github.com/tdamdouni/Pythonista/blob/master/contacts/Add%20Twitter%20Profile%20Picture%20to%20iOS%20Contacts.py
predicate_contacts = CNContactStore.unifiedContactsMatchingPredicate_keysToFetch_error_(predicate, ['familyName','givenName','middleName'], None)
for contact in predicate_contacts:
# crash if attribute not in fetched contacts
name = str(contact.givenName()) + '|' + str(contact.middleName()) + '|' + str(contact.familyName())
objc_contacts[name] = id
# Pythonista contacts
all_contacts = contacts.get_all_people()
for person in all_contacts:
key = person.first_name + '|' + person.middle_name + '|' + person.last_name
id = '****'
if key in objc_contacts:
id = objc_contacts[key]
print(key, id)
@cvp, works for me, thanks!
I can get a semi-legible name for the container with:
print(container.name(), '-', container.descriptionForContainerType_(container.type()))
... but from the contents I am still not sure which are from Gmail - ”Address Book - CardDav” or ”Personal Contacts - Exchange”...
@mikael I can't help. Perhaps by putting one contact only in one account?
Looks like Gmail is the ”Address Book”/”CardDAV” container. People being in more than one container was throwing me off.
@cvp, I adjusted your code a little to show repeated entries for people in more than one container:
from objc_util import *
import contacts
# ObjectiveC contacts
objc_contacts = {}
CNContactStore = ObjCClass('CNContactStore').alloc().init()
CNContact = ObjCClass('CNContact')
Containers = CNContactStore.containersMatchingPredicate_error_(None,None)
containers = {}
for Container in Containers:
id = Container.identifier()
containers[id] = Container
#print(dir(Container))
predicate = CNContact.predicateForContactsInContainerWithIdentifier_(id)
# keys not exactly like in Apple doc
# found a sample here https://github.com/tdamdouni/Pythonista/blob/master/contacts/Add%20Twitter%20Profile%20Picture%20to%20iOS%20Contacts.py
predicate_contacts = CNContactStore.unifiedContactsMatchingPredicate_keysToFetch_error_(predicate, ['familyName','givenName','middleName'], None)
for contact in predicate_contacts:
# crash if attribute not in fetched contacts
name = str(contact.givenName()) + '|' + str(contact.middleName()) + '|' + str(contact.familyName())
cont_per_name = objc_contacts.setdefault(name, [])
cont_per_name.append(id)
# Pythonista contacts
all_contacts = contacts.get_all_people()
for person in all_contacts:
key = person.first_name + '|' + person.middle_name + '|' + person.last_name
id = '****'
if key in objc_contacts:
for id in objc_contacts[key]:
container = containers[id]
print(key, '-', container.name(), '-', container.descriptionForContainerType_(container.type()))
@mikael 👍thanks
@mikael Could you edit your post to replace "adjusted" by "improved" 😀
@cvp, no, thank you - I would not have had the time for the ObjC gymnastics at this time.
@mikael I agree that, with my very small knowledge about ObjC, I spend sometimes a lot of hours to finally write a so little script, but I have this time as retired 👴🏻
Matching by the name...
Is this the only way to correlate Pythonista contacts person.id and CNContact identifier()? 😟