TweetFollow Us on Twitter

Mac in the Shell: Accessing AddressBook with PyObjC

Volume Number: 25
Issue Number: 08
Column Tag: Mac in the Shell

Mac in the Shell: Accessing AddressBook with PyObjC

Using a specific Cocoa API from Python

by Edward Marczak

Introduction

Last month, we covered some basic text parsing using Python. I personally love the topic, as it's really applicable across a wide range of problems. But it was also fairly generic: that code will run on any platform with Python installed. Better yet: we can combine the text processing of standard Python with the OS X-specific PyObj-C libraries that let us tie into Cocoa APIs. This month, we'll look at AddressBook.

Accessing Address Book

First thing to remember: PyObj-C support is only built-in to OS 10.5 and above and with Python v2.5 and greater. If you're on a 10.4 system, this will not work out of the box. You'll need to get pyobjc support installed for 10.4 for yourself (further information and instructions can be found at http://pyobjc.sourceforge.net/downloads.html). This works just fine under 10.5 and, ummmmm... a certain future operating system.

The AddressBook framework in OS X is well documented by Apple. The developer site has plenty of information. A good starting point can be found at http://developer.apple.com/documentation/userexperience/Conceptual/AddressBook/AddressBook.html. All of the code presented in this article was written based on this documentation.

The code we'll look at this month is a small snippet of code that I actually use. As Executive Editor for MacTech, I send out a 'nag' message each month to authors that due dates are coming up. (Yes, I'm looking to automate this, but honestly like the personal touch that sending it out manually provides). I keep a group in AddressBook with the authors that have requested that I send them a reminder. Sometimes I use Mail.app, but sometimes I'm using a web-based mail interface that does not contain my contacts. Thanks to the magic of MobileMe, I tend to have my AddressBook no matter which machine I'm logged into. So then, what I need each month is a list of each address in the group I call "MacTech Editorial".

Like last month, I marvel at how little code we need to accomplish this. Here's the entire listing:

Listing 1 – MTDumpABGroup.py

#!/usr/bin/python2.5
import sys
from AddressBook import *
def GetAllABGroups(abref):
  groupdict = {}
  abgroups = abref.groups()
  for abgroup in abgroups:
    groupdict[abgroup.name()] = [abgroup.uniqueId()]
  return groupdict
def GetAllABListEmails(abref, abgroupid):
  address_dict = {}
  abgroup = abref.recordForUniqueId_(abgroupid)
  card = abgroup.members()
  for entity in card:
    emails = entity.valueForProperty_(kABEmailProperty)
    if emails is not None:
      address_dict[entity.uniqueId()] = emails.valueAtIndex_(0)
  return address_dict
def main():
  ab = ABAddressBook.sharedAddressBook()
  groups = GetAllABGroups(ab)
  groupid = None
  for group in groups:
    if group == "MacTech Editorial":
      groupid = groups[group][0]
      break
  if groupid is None:
    print "Group not found"
    sys.exit(1)
  addresses = GetAllABListEmails(ab, groupid)
  for i in addresses:
    print addresses[i] + ",",
if __name__ == '__main__':
  main()

Analyzing the code

Despite the brevity of the code involved, there's still some explaining to do. I'll follow the code as it executes, rather than go line-by-line from the top to the bottom. The only exceptions to that is the import statement at the top of the file (which does execute first). We need to import the AddressBook library for any of this to work, which is what make our job easy: Apple has already done the grunt work and we just need to exploit it.

The first statement to execute is the second to last: "if __name__..." This is the standard Python-ism that we've discussed in the past. This allows another Python app to import our program without running it. If we are running stand-alone, though, main() gets called.

First, in main(), we need a reference to the system's shared AddressBook. We instantiate a new copy of the ABAddressBook class and assign it to ab. Next, that reference gets passed into our GetGroups() function.

GetGroups() is more of a convenience function than anything, as we're really only going to use it once, but it's a decent illustration on pulling out all groups listed in the current user's address book. How do we obtain the list of groups in the address book? We ask! The groups() method returns an array of each group. In turn, each group has properties that can be obtained. In our case, we only care about the name, because as humans, that how we tend to identify things, and the group's unique ID, as we'll need to use that to request the members of the group. This function simply defines a dictionary that we fill with the requisite information. Once filled, we return that value from the function.

Back in main(), we simply loop though the groups that were returned, by name, and look for the one we're interested in. In our case, as mentioned, we're after the group named "MacTech Editorial". Once we find what we're looking for, we break out of the loop.

You'll notice that we set groupid to None prior to entering the loop. This just makes it easier for us to test if groupid has a value or not. Since it only gets set if we found the group we're looking for we use that in an if conditional:

if groupid is None:
    print "Group not found"
    sys.exit(1)

If groupid is still None when we exit the loop, we haven't found the group we're looking for and print a message and then exit with an exit code. It's useful to set a proper exit code so you can test for this in a shell script.

As an aside, another way to accomplish this would be to use a try block, but I found that a little more cumbersome for this program. Using a try block would eliminate the need to set groupid to None prior to entering the loop:

try:
  groupid
except NameError:
  print "Group not found"
  sys.exit(1)

For this particular endeavor, either method will suffice, however, I've gone with the "define as None" method above.

Once we've found the unique ID for the group we want to dump, we pass that off to GetAllListEmails(). First, we define a dictionary, addressdict, that will hold the addresses. Next, retrieve the address book group record that matches the given unique ID with recordForUniqueId. From there, we can gather all of the members of the group. How? We ask! The AddressBook Group class reference documentation lists the member method. The remainder of this function relies on the results returned from this call. A simple Python for loop allows us access to each person retrieved. Now, an AddressBook card may contain an entry that does not have an e-mail address, which is all we're really interested in. So, we retrieve all e-mail addresses associated with the card with the line:

emails = entity.valueForProperty_(kABEmailProperty)

This returns a multi-value of e-mail addresses attached to the card. For the purposes here, I'm only interested in one, and I'll take the first that's returned. But first, we need to see if any addresses were returned at all. The if conditional checks for addresses, and if some were returned, we'll take the first and add it to our dictionary:

address_dict[entity.uniqueId()] = emails.valueAtIndex_(0)

Once we've looped through all people returned, we have the dictionary we need. Time to return that back to the calling function.

Delivering the Results

Now for the easy part: printing out the results. We've covered looping through a Python dictionary plenty of times before, and that's all that's happening here:

for i in addresses:
  print addresses[i] + ",",

So, time to run the application! Naturally, you'll need to substitute an appropriate group name on line 31 (if group == "MacTech Editorial":) for a group that you have in your address book. Don't forget to chmod it as executable (chmod 770 MTDumpABGroup.py), and then go for it:

./MTDumpABGroup.py

bob@example.com, scott@example.net, bruce@mactech.com, wendel@example.org, alice@example.co.uk,

Thanks to one of OS X's many integrations between the shell and GUI, we can make our lives easier by piping the output into pbcopy:

./MTDumpABGroup | pbcopy

...and then just paste it into the To: field in your e-mail application (if it does indeed accept the address-comma-address format. I'm hard pressed to think of an e-mail client that doesn't, but I won't say one doesn't exist). You may need to drop the trailing comma, but since I've been using Gmail which just ignores the trailing comma, I just past the whole thing in.

Conclusion

In just 43 lines, including the stylistic spacing, we have a script that will dump all of the e-mail addresses associated with a particular group in Address Book. This example should illustrate several things: first, it's not difficult to get Cocoa via Python. It's well documented. Second, you don't have to spend a lifetime trying to find a solution. My itch (getting a list of e-mail addresses from a particular group) was easily scratched.

Media of the month: My reading list has become incredibly long...so much to read! But I gravitated toward a particular book in my pile (by the way – I really do prefer books. As in the real, physical variety. Perhaps it's just tactile, but, no Kindle for me yet). "Brewing Up a Business: Adventures in Entrepreneurship" by Sam Calagione seemed to be beckoning. Now, this may be the first book that I'm recommending before I actually finish it. I'm about three-fifths of the way through. It's so far really enjoyable. It's targeted at people starting their own business, so, for the consultants and potential consultants out there, it seems like something that should be on your reading list.

Until next month, keep practicing Python!

References

Address Book Class Reference: http://developer.apple.com/documentation/userexperience/Reference/AddressBook/Classes/ABAddressBook_Class/Reference/Reference.html#//apple_ref/occ/instm/ABAddressBook/people

Address Book Group Reference: http://developer.apple.com/documentation/UserExperience/Reference/AddressBook/Classes/ABGroup_Class/Reference/Reference.html

Address Book Person Reference: http://developer.apple.com/documentation/UserExperience/Reference/AddressBook/C/ABPersonRef/Reference/reference.html


Ed Marczak is the Executive Editor of MacTech Magazine. He has written for MacTech since 2004.

 
AAPL
$565.89
Apple Inc.
+41.14
MSFT
$39.36
Microsoft Corpora
-0.33
GOOG
$524.16
Google Inc.
-2.78

MacTech Search:
Community Search:

Software Updates via MacUpdate

TechTool Pro 7.0.3 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
MacFamilyTree 7.1.6 - Create and explore...
MacFamilyTree gives genealogy a facelift: it's modern, interactive, incredibly fast, and easy to use. We're convinced that generations of chroniclers would have loved to trade in their genealogy... Read more
EtreCheck 1.9.9 - For troubleshooting yo...
EtreCheck is a simple little app to display the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support... Read more
TeamViewer 9.0.28116 - Establish remote...
TeamViewer gives you remote control of any computer or Mac over the Internet within seconds, or can be used for online meetings. Find out why more than 200 million users trust TeamViewer! Free for... Read more
Viber 4.1.0 - Send messages and make cal...
Viber lets you send free messages and make free calls to other Viber users, on any device and network, in any country! Viber syncs your contacts, messages and call history with your mobile device,... Read more
Apple iOS 7.1.1 - The latest version of...
The latest version of iOS can be downloaded through iTunes. Apple iOS 7 brings an all-new design and all-new features. Simplicity Simplicity is often equated with minimalism. Yet true simplicity is... Read more
1Password 4.3 - Powerful password manage...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
Lens Blur 1.3.0 - True out-of-focus boke...
Let Lens Blur transform your existing photo into true SLR-quality out-of-focus bokeh effect! Everyone needs a gorgeous personalized background for a social profile, blog, Web/UI design, presentation... Read more
VMware Fusion 6.0.3 - Run Windows apps a...
VMware Fusion allows you to create a Virtual Machine on your Mac and run Windows (including Windows 8.1) and Windows software on your Mac. Run your favorite Windows applications alongside Mac... Read more
BitTorrent Sync 1.3.93 - Sync files secu...
BitTorrent Sync allows you to sync unlimited files between your own devices, or share a folder with friends and family to automatically sync anything. File transfers are encrypted. Your information... Read more

Latest Forum Discussions

See All

Spin It Review
Spin It Review By Jordan Minor on April 24th, 2014 Our Rating: :: SPIN ME RIGHT ROUNDUniversal App - Designed for iPhone and iPad Spin It has a fine puzzle game model, but its execution lacks energy.   | Read more »
The Sandbox Gets Update, Receives New Ca...
The Sandbox Gets Update, Receives New Campaign and New Elements Posted by Tre Lawrence on April 24th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Football Management Simulator One For El...
Football Management Simulator One For Eleven Released Worldwide Today for iOS Posted by Simon Reed on April 24th, 2014 [ permalink ] Free-To-Play football management title One For E | Read more »
Leo’s Fortune Review
Leo’s Fortune Review By Jordan Minor on April 24th, 2014 Our Rating: :: FORTUNATE SONUniversal App - Designed for iPhone and iPad Leo’s Fortune delivers a platforming experience as creative and refined as any console game.   | Read more »
Suited Up (Games)
Suited Up 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Suited Up is a difficult, one-touch platformer that requires players to visualize each jump. The controls in Suited Up are simple,... | Read more »
MyTP One Mountain - Ski, Freeski and Sno...
MyTP One Mountain - Ski, Freeski and Snowboard 1.0.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0.0 (iTunes) Description: As real snow is melting away in the snow parks around the northern hemisphere, it's now time... | Read more »
Tank Battle: East Front 1943 (Games)
Tank Battle: East Front 1943 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Tank Battle: East Front 1943 is the third in the successful ‘Tank Battle: East Front’ series of games for iPhone... | Read more »
Third Eye Crime: Act 1 (Games)
Third Eye Crime: Act 1 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: "You have to see Third Eye Crime" Touch Arcade "Third Eye Crime is unlike anything currently available for mobile... | Read more »
Wayward Souls (Games)
Wayward Souls 1.00 Device: iOS Universal Category: Games Price: $4.99, Version: 1.00 (iTunes) Description: **Buy the game now at an introductory sale price of $4.99 USD. Every time we do a big content update, we will raise the price... | Read more »
Leo's Fortune (Games)
Leo's Fortune 1.0.2 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.2 (iTunes) Description: Leo’s Fortune is a platform adventure game where you hunt down the cunning and mysterious thief that stole your gold.... | Read more »

Price Scanner via MacPrices.net

16GB 1st generation iPad mini available for $...
Radio Shack has a select number of refurbished 1st generation 16GB WiFi iPad minis available for $199.99 on their online store. Choose free shipping or free ship-to-store. We expect these to sell out... Read more
13-inch 2.5GHz MacBook Pro on sale for $100 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $1099 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
iPad Sales “Lull” A Reality Correction Of Unm...
I have lots of time for Jean-Louis Gassée, the former Apple Computer executive (1981 to 1990) who succeeded Steve Jobs as head of Macintosh development when the latter was dismissed in 1985. Mr.... Read more
Apple Makes OS X Betas Available To All – Wit...
Apple’s OS X Beta Seed Program, which lets you install the latest pre-release builds, try it out, and submit your feedback, is now open to anyone who wants to sign on rather than to developers and... Read more
Apple Releases iOS 7.1.1 Update
The latest iOS 7.1.1 update contains improvements, bug fixes and security updates, including: • Further improvements to Touch ID fingerprint recognition • Fixes a bug that could impact keyboard... Read more
Logitech Announces Thinner, Lighter, More Fle...
Logitech has announced an update to its Ultrathin for iPad Air, iPad mini and iPad mini with Retina display, improving the flexibility and design of its award-winning predecessor with an even thinner... Read more
Logitech Introduces Hinge, Big Bang and Turna...
Logitech has announced expansion of its tablet product line with three new cases – the Logitech Hinge, the Logitech Big Bang and the Logitech Turnaround – each for the iPad Air, iPad mini and iPad... Read more
WaterField’s Rough Rider Leather Messenger Ba...
WaterField Designs have announced the new 15-inch size of their popular Rough Rider leather messenger bag, a vintage-looking bag that combines Old West charm and ruggedness with distinctly modern... Read more
New Mac Pro on sale, save $100 on the 4-Core...
J&R has the new 4-Core Mac Pro in stock today and on sale for $2899 including free shipping plus NY sales tax only. Their price is $100 off MSRP, and it’s the lowest price available for this... Read more
Apple refurbished iMacs available for up to $...
The Apple Store has Apple Certified Refurbished 2013 iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. - 27″ 3.4GHz iMac – $1699... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Inc. Research Data Specialist - Appl...
…of Worldwide Market Research & Intelligence. The team is responsible for conducting Apple branded consumer market research. It is also responsible for analyzing data Read more
*Apple* Automotive Parts Department position...
Apple Automotive is one of the fastest growing dealer…and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive, we Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.