PyiCloud is a module which allows pythonistas to interact with iCloud webservices. It's powered by the fantastic `requests <https://github.com/kennethreitz/requests>`_ HTTP library.
You can also store your password in the system keyring using the command-line tool:
>>> icloud --username=jappleseed@apple.com
ICloud Password for jappleseed@apple.com:
Save password in keyring? (y/N)
If you have stored a password in the keyring, you will not be required to provide a password when interacting with the command-line tool or instantiating the ``PyiCloudService`` class for the username you stored the password for.
>>> api = PyiCloudService('jappleseed@apple.com')
If you would like to delete a password stored in your system keyring, you can clear a stored password using the ``--delete-from-keyring`` command-line option:
If you have enabled two-factor authentication for the account you will have to do some extra work:
..code-block:: python
if icloud.requires_2fa:
print "Two-factor authentication required. Your trusted devices are:"
devices = icloud.trusted_devices
for i, device in enumerate(devices):
print " %s: %s" % (i, device.get('deviceName',
"SMS to %s" % device.get('phoneNumber')))
device = click.prompt('Which device would you like to use?', default=0)
device = devices[device]
if not icloud.send_verification_code(device):
print "Failed to send verification code"
sys.exit(1)
code = click.prompt('Please enter validation code')
if not icloud.validate_verification_code(device, code):
print "Failed to verify verification code"
sys.exit(1)
Note: Both regular login and two-factor authentication will expire after an interval set by Apple, at which point you will have to re-authenticate. This interval is currently two months.
or, as a shorthand if you have only one associated apple device, you can simply use the ``iphone`` property to access the first device associated with your account:
If you wish to request further properties, you may do so by passing in a list of property names.
**********
Play Sound
**********
Sends a request to the device to play a sound, if you wish pass a custom message you can do so by changing the subject arg.
>>> api.iphone.play_sound()
A few moments later, the device will play a ringtone, display the default notification ("Find My iPhone Alert") and a confirmation email will be sent to you.
*********
Lost Mode
*********
Lost mode is slightly different to the "Play Sound" functionality in that it allows the person who picks up the phone to call a specific phone number *without having to enter the passcode*. Just like "Play Sound" you may pass a custom message which the device will display, if it's not overridden the custom message of "This iPhone has been lost. Please call me." is used.
>>> phone_number = '555-373-383'
>>> message = 'Thief! Return my phone immediately.'
>>> api.iphone.lost_device(phone_number, message)
========
Calendar
========
The calendar webservice currently only supports fetching events.
******
Events
******
Returns this month's events:
>>> api.calendar.events()
Or, between a specific date range:
>>> from_dt = datetime(2012, 1, 1)
>>> to_dt = datetime(2012, 1, 31)
>>> api.calendar.events(from_dt, to_dt)
Alternatively, you may fetch a single event's details, like so:
Note: the object returned from the above ``open`` method is a `response object <http://www.python-requests.org/en/latest/api/#classes>`_ and the ``open`` method can accept any parameters you might normally use in a request using `requests <https://github.com/kennethreitz/requests>`_.
Or, if you're downloading a particularly large file, you may want to use the ``stream`` keyword argument, and read directly from the raw response object:
You can access the iCloud Photo Library through the ``photos`` property.
>>> api.photos.all
<PhotoAlbum: 'All Photos'>
Individual albums are available through the ``albums`` property:
>>> api.photos.albums['Selfies']
<PhotoAlbum: 'Selfies'>
Which you can index or iterate to access the photo assets:
>>> for photo in api.photos.albums['Selfies']:
print photo, photo.filename
<PhotoAsset: client_id=4429> IMG_6045.JPG
Metadata about photos is fetched on demand as you access properties of the ``PhotoAsset`` object, and are also prefetched to improve performance.
To download a photo use the `download` method, which will return a `response object <http://www.python-requests.org/en/latest/api/#classes>`_, initialized with ``stream`` set to ``True``, so you can read from the raw response object:
>>> photo = api.photos.albums['Selfies'][0]
>>> download = photo.download()
>>> with open(photo.filename, 'wb') as opened_file:
opened_file.write(download.raw.read())
Note: Consider using ``shutil.copyfile`` or another buffered strategy for downloading the file so that the whole file isn't read into memory before writing.
Information about each version can be accessed through the ``versions`` property:
>>> photo.versions.keys()
[u'large', u'medium', u'original', u'thumb']
To download a specific version of the photo asset, pass the version to ``download()``:
>>> download = photo.download('thumb')
>>> with open(photo.versions['thumb'].filename, 'wb') as thumb_file: