Skip to main content

PyiCloud is a module which allows pythonistas to interact with iCloud webservices.

Project description

Check out our test status at https://travis-ci.org/picklepete/pyicloud Library version Supported versions Downloads Requirements Status Formated with Black Join the chat at https://gitter.im/picklepete/pyicloud

PyiCloud is a module which allows pythonistas to interact with iCloud webservices. It’s powered by the fantastic requests HTTP library.

At its core, PyiCloud connects to iCloud using your username and password, then performs calendar and iPhone queries against their API.

Authentication

Authentication without using a saved password is as simple as passing your username and password to the PyiCloudService class:

>>> from pyicloud import PyiCloudService
>>> api = PyiCloudService('jappleseed@apple.com', 'password')

In the event that the username/password combination is invalid, a PyiCloudFailedLoginException exception is thrown.

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:

>>> icloud --username=jappleseed@apple.com --delete-from-keyring

Note: Authentication will expire after an interval set by Apple, at which point you will have to re-authenticate. This interval is currently two months.

Two-step and two-factor authentication (2SA/2FA)

If you have enabled two-step authentication (2SA) for the account you will have to do some extra work:

if api.requires_2sa:
    import click
    print "Two-step authentication required. Your trusted devices are:"

    devices = api.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 api.send_verification_code(device):
        print "Failed to send verification code"
        sys.exit(1)

    code = click.prompt('Please enter validation code')
    if not api.validate_verification_code(device, code):
        print "Failed to verify verification code"
        sys.exit(1)

This approach also works if the account is set up for two-factor authentication (2FA), but the authentication will time out after a few hours. Full support for two-factor authentication (2FA) is not implemented in PyiCloud yet. See issue #102.

Devices

You can list which devices associated with your account by using the devices property:

>>> api.devices
{
u'i9vbKRGIcLYqJnXMd1b257kUWnoyEBcEh6yM+IfmiMLh7BmOpALS+w==': <AppleDevice(iPhone 4S: Johnny Appleseed's iPhone)>,
u'reGYDh9XwqNWTGIhNBuEwP1ds0F/Lg5t/fxNbI4V939hhXawByErk+HYVNSUzmWV': <AppleDevice(MacBook Air 11": Johnny Appleseed's MacBook Air)>
}

and you can access individual devices by either their index, or their ID:

>>> api.devices[0]
<AppleDevice(iPhone 4S: Johnny Appleseed's iPhone)>
>>> api.devices['i9vbKRGIcLYqJnXMd1b257kUWnoyEBcEh6yM+IfmiMLh7BmOpALS+w==']
<AppleDevice(iPhone 4S: Johnny Appleseed's iPhone)>

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:

>>> api.iphone
<AppleDevice(iPhone 4S: Johnny Appleseed's iPhone)>

Note: the first device associated with your account may not necessarily be your iPhone.

Find My iPhone

Once you have successfully authenticated, you can start querying your data!

Location

Returns the device’s last known location. The Find My iPhone app must have been installed and initialized.

>>> api.iphone.location()
{u'timeStamp': 1357753796553, u'locationFinished': True, u'longitude': -0.14189, u'positionType': u'GPS', u'locationType': None, u'latitude': 51.501364, u'isOld': False, u'horizontalAccuracy': 5.0}

Status

The Find My iPhone response is quite bloated, so for simplicity’s sake this method will return a subset of the properties.

>>> api.iphone.status()
{'deviceDisplayName': u'iPhone 5', 'deviceStatus': u'200', 'batteryLevel': 0.6166913, 'name': u"Peter's iPhone"}

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:

>>> api.calendar.get_event_detail('CALENDAR', 'EVENT_ID')

Contacts

You can access your iCloud contacts/address book through the contacts property:

>>> for c in api.contacts.all():
>>> print c.get('firstName'), c.get('phones')
John [{u'field': u'+1 555-55-5555-5', u'label': u'MOBILE'}]

Note: These contacts do not include contacts federated from e.g. Facebook, only the ones stored in iCloud.

File Storage (Ubiquity)

You can access documents stored in your iCloud account by using the files property’s dir method:

>>> api.files.dir()
[u'.do-not-delete',
 u'.localized',
 u'com~apple~Notes',
 u'com~apple~Preview',
 u'com~apple~mail',
 u'com~apple~shoebox',
 u'com~apple~system~spotlight'
]

You can access children and their children’s children using the filename as an index:

>>> api.files['com~apple~Notes']
<Folder: u'com~apple~Notes'>
>>> api.files['com~apple~Notes'].type
u'folder'
>>> api.files['com~apple~Notes'].dir()
[u'Documents']
>>> api.files['com~apple~Notes']['Documents'].dir()
[u'Some Document']
>>> api.files['com~apple~Notes']['Documents']['Some Document'].name
u'Some Document'
>>> api.files['com~apple~Notes']['Documents']['Some Document'].modified
datetime.datetime(2012, 9, 13, 2, 26, 17)
>>> api.files['com~apple~Notes']['Documents']['Some Document'].size
1308134
>>> api.files['com~apple~Notes']['Documents']['Some Document'].type
u'file'

And when you have a file that you’d like to download, the open method will return a response object from which you can read the content.

>>> api.files['com~apple~Notes']['Documents']['Some Document'].open().content
'Hello, these are the file contents'

Note: the object returned from the above open method is a response object and the open method can accept any parameters you might normally use in a request using requests.

For example, if you know that the file you’re opening has JSON content:

>>> api.files['com~apple~Notes']['Documents']['information.json'].open().json()
{'How much we love you': 'lots'}
>>> api.files['com~apple~Notes']['Documents']['information.json'].open().json()['How much we love you']
'lots'

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:

>>> download = api.files['com~apple~Notes']['Documents']['big_file.zip'].open(stream=True)
>>> with open('downloaded_file.zip', 'wb') as opened_file:
        opened_file.write(download.raw.read())

Photo Library

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['Screenshots']
<PhotoAlbum: 'Screenshots'>

Which you can iterate to access the photo assets. The ‘All Photos’ album is sorted by added_date so the most recently added photos are returned first. All other albums are sorted by asset_date (which represents the exif date) :

>>> for photo in api.photos.albums['Screenshots']:
        print photo, photo.filename
<PhotoAsset: id=AVbLPCGkp798nTb9KZozCXtO7jds> IMG_6045.JPG

To download a photo use the download method, which will return a response object, initialized with stream set to True, so you can read from the raw response object:

>>> photo = next(iter(api.photos.albums['Screenshots']), None)
>>> 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'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:
        thumb_file.write(download.raw.read())

Code samples

If you wanna see some code samples see the code samples file.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyicloud-0.9.7.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

pyicloud-0.9.7-py3-none-any.whl (26.3 kB view details)

Uploaded Python 3

File details

Details for the file pyicloud-0.9.7.tar.gz.

File metadata

  • Download URL: pyicloud-0.9.7.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/46.1.3 requests-toolbelt/0.9.1 tqdm/4.44.1 CPython/3.7.7

File hashes

Hashes for pyicloud-0.9.7.tar.gz
Algorithm Hash digest
SHA256 dcebb32e474bc28aa77b944a0a64949ef3b5b852cbef6256fbc95347a04e777c
MD5 4e34f96e8afb69d3e27e9c5075798eb8
BLAKE2b-256 195f6a7154af2629d63b76f84359f6fc32aed849139ccb4245436da4443ac8a1

See more details on using hashes here.

File details

Details for the file pyicloud-0.9.7-py3-none-any.whl.

File metadata

  • Download URL: pyicloud-0.9.7-py3-none-any.whl
  • Upload date:
  • Size: 26.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/46.1.3 requests-toolbelt/0.9.1 tqdm/4.44.1 CPython/3.7.7

File hashes

Hashes for pyicloud-0.9.7-py3-none-any.whl
Algorithm Hash digest
SHA256 e1a366813044c7c950f6ce966e6290996f4cc0f1d1184151856db7191f4de0db
MD5 c5845ed2b6c037437597f780f3500d95
BLAKE2b-256 5c5b4d1fd61abc9f17cfb9ff0ce05c67f7b91ba2072f8fb7e6042316b5e539ec

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page