Add iCloud Drive support (#278)
* Initial version of the iCloud drive client * Pylint & black * Add tests + some fixes * Fix pipe Co-authored-by: Herve Saint-Amand <herve@brainnwave.com>
This commit is contained in:
parent
696db8cf20
commit
e6429b9ada
14 changed files with 1032 additions and 13 deletions
27
README.rst
27
README.rst
|
@ -247,6 +247,33 @@ Or, if you're downloading a particularly large file, you may want to use the ``s
|
||||||
>>> with open('downloaded_file.zip', 'wb') as opened_file:
|
>>> with open('downloaded_file.zip', 'wb') as opened_file:
|
||||||
opened_file.write(download.raw.read())
|
opened_file.write(download.raw.read())
|
||||||
|
|
||||||
|
File Storage (iCloud Drive)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
You can access your iCloud Drive using an API identical to the Ubiquity one described in the previous section, except that it is rooted at ```api.drive```:
|
||||||
|
|
||||||
|
>>> api.drive.dir()
|
||||||
|
['Holiday Photos', 'Work Files']
|
||||||
|
>>> api.drive['Holiday Photos']['2013']['Sicily'].dir()
|
||||||
|
['DSC08116.JPG', 'DSC08117.JPG']
|
||||||
|
|
||||||
|
>>> drive_file = api.drive['Holiday Photos']['2013']['Sicily']['DSC08116.JPG']
|
||||||
|
>>> drive_file.name
|
||||||
|
u'DSC08116.JPG'
|
||||||
|
>>> drive_file.modified
|
||||||
|
datetime.datetime(2013, 3, 21, 12, 28, 12) # NB this is UTC
|
||||||
|
>>> drive_file.size
|
||||||
|
2021698
|
||||||
|
>>> drive_file.type
|
||||||
|
u'file'
|
||||||
|
|
||||||
|
The ``open`` method will return a response object from which you can read the file's contents:
|
||||||
|
|
||||||
|
>>> from shutil import copyfileobj
|
||||||
|
>>> with drive_file.open(stream=True) as response:
|
||||||
|
>>> with open(drive_file.name, 'wb') as file_out:
|
||||||
|
>>> copyfileobj(response.raw, file_out)
|
||||||
|
|
||||||
|
|
||||||
Photo Library
|
Photo Library
|
||||||
=======================
|
=======================
|
||||||
|
|
|
@ -24,6 +24,7 @@ from pyicloud.services import (
|
||||||
RemindersService,
|
RemindersService,
|
||||||
PhotosService,
|
PhotosService,
|
||||||
AccountService,
|
AccountService,
|
||||||
|
DriveService,
|
||||||
)
|
)
|
||||||
from pyicloud.utils import get_password_from_keyring
|
from pyicloud.utils import get_password_from_keyring
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ class PyiCloudSession(Session):
|
||||||
|
|
||||||
request_logger.debug(data)
|
request_logger.debug(data)
|
||||||
|
|
||||||
|
if isinstance(data, dict):
|
||||||
reason = data.get("errorMessage")
|
reason = data.get("errorMessage")
|
||||||
reason = reason or data.get("reason")
|
reason = reason or data.get("reason")
|
||||||
reason = reason or data.get("errorReason")
|
reason = reason or data.get("errorReason")
|
||||||
|
@ -207,6 +209,7 @@ class PyiCloudService(object):
|
||||||
|
|
||||||
self.authenticate()
|
self.authenticate()
|
||||||
|
|
||||||
|
self._drive = None
|
||||||
self._files = None
|
self._files = None
|
||||||
self._photos = None
|
self._photos = None
|
||||||
|
|
||||||
|
@ -361,6 +364,18 @@ class PyiCloudService(object):
|
||||||
service_root = self._get_webservice_url("reminders")
|
service_root = self._get_webservice_url("reminders")
|
||||||
return RemindersService(service_root, self.session, self.params)
|
return RemindersService(service_root, self.session, self.params)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def drive(self):
|
||||||
|
"""Gets the 'Drive' service."""
|
||||||
|
if not self._drive:
|
||||||
|
self._drive = DriveService(
|
||||||
|
service_root=self._get_webservice_url("drivews"),
|
||||||
|
document_root=self._get_webservice_url("docws"),
|
||||||
|
session=self.session,
|
||||||
|
params=self.params,
|
||||||
|
)
|
||||||
|
return self._drive
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "iCloud API: %s" % self.user.get("apple_id")
|
return "iCloud API: %s" % self.user.get("apple_id")
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,4 @@ from pyicloud.services.contacts import ContactsService
|
||||||
from pyicloud.services.reminders import RemindersService
|
from pyicloud.services.reminders import RemindersService
|
||||||
from pyicloud.services.photos import PhotosService
|
from pyicloud.services.photos import PhotosService
|
||||||
from pyicloud.services.account import AccountService
|
from pyicloud.services.account import AccountService
|
||||||
|
from pyicloud.services.drive import DriveService
|
||||||
|
|
172
pyicloud/services/drive.py
Normal file
172
pyicloud/services/drive.py
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
"""Drive service."""
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import json
|
||||||
|
from re import search
|
||||||
|
from six import PY2
|
||||||
|
|
||||||
|
|
||||||
|
class DriveService(object):
|
||||||
|
"""The 'Drive' iCloud service."""
|
||||||
|
|
||||||
|
def __init__(self, service_root, document_root, session, params):
|
||||||
|
self._service_root = service_root
|
||||||
|
self._document_root = document_root
|
||||||
|
self.session = session
|
||||||
|
self.params = dict(params)
|
||||||
|
self._root = None
|
||||||
|
|
||||||
|
def _get_token_from_cookie(self):
|
||||||
|
for cookie in self.session.cookies:
|
||||||
|
if cookie.name == "X-APPLE-WEBAUTH-TOKEN":
|
||||||
|
match = search(r"\bt=([^:]+)", cookie.value)
|
||||||
|
if not match:
|
||||||
|
raise Exception("Can't extract token from %r" % cookie.value)
|
||||||
|
self.params.update({"token": match.group(1)})
|
||||||
|
raise Exception("Token cookie not found")
|
||||||
|
|
||||||
|
def get_node_data(self, node_id):
|
||||||
|
"""Returns the node data."""
|
||||||
|
request = self.session.post(
|
||||||
|
self._service_root + "/retrieveItemDetailsInFolders",
|
||||||
|
params=self.params,
|
||||||
|
data=json.dumps(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"drivewsid": "FOLDER::com.apple.CloudDocs::%s" % node_id,
|
||||||
|
"partialData": False,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return request.json()[0]
|
||||||
|
|
||||||
|
def get_file(self, file_id, **kwargs):
|
||||||
|
"""Returns iCloud Drive file."""
|
||||||
|
file_params = dict(self.params)
|
||||||
|
file_params.update({"document_id": file_id})
|
||||||
|
response = self.session.get(
|
||||||
|
self._document_root + "/ws/com.apple.CloudDocs/download/by_id",
|
||||||
|
params=file_params,
|
||||||
|
)
|
||||||
|
if not response.ok:
|
||||||
|
return None
|
||||||
|
url = response.json()["data_token"]["url"]
|
||||||
|
return self.session.get(url, params=self.params, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def root(self):
|
||||||
|
"""Returns the root node."""
|
||||||
|
if not self._root:
|
||||||
|
self._root = DriveNode(self, self.get_node_data("root"))
|
||||||
|
return self._root
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.root, attr)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.root[key]
|
||||||
|
|
||||||
|
|
||||||
|
class DriveNode(object):
|
||||||
|
"""Drive node."""
|
||||||
|
|
||||||
|
def __init__(self, conn, data):
|
||||||
|
self.data = data
|
||||||
|
self.connection = conn
|
||||||
|
self._children = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Gets the node name."""
|
||||||
|
if self.type == "file":
|
||||||
|
return "%s.%s" % (self.data["name"], self.data["extension"])
|
||||||
|
return self.data["name"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
"""Gets the node type."""
|
||||||
|
node_type = self.data.get("type")
|
||||||
|
return node_type and node_type.lower()
|
||||||
|
|
||||||
|
def get_children(self):
|
||||||
|
"""Gets the node children."""
|
||||||
|
if not self._children:
|
||||||
|
if "items" not in self.data:
|
||||||
|
self.data.update(self.connection.get_node_data(self.data["docwsid"]))
|
||||||
|
if "items" not in self.data:
|
||||||
|
raise KeyError("No items in folder, status: %s" % self.data["status"])
|
||||||
|
self._children = [
|
||||||
|
DriveNode(self.connection, item_data)
|
||||||
|
for item_data in self.data["items"]
|
||||||
|
]
|
||||||
|
return self._children
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self):
|
||||||
|
"""Gets the node size."""
|
||||||
|
size = self.data.get("size") # Folder does not have size
|
||||||
|
if not size:
|
||||||
|
return None
|
||||||
|
return int(size)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def date_changed(self):
|
||||||
|
"""Gets the node changed date (in UTC)."""
|
||||||
|
return _date_to_utc(self.data.get("dateChanged")) # Folder does not have date
|
||||||
|
|
||||||
|
@property
|
||||||
|
def date_modified(self):
|
||||||
|
"""Gets the node modified date (in UTC)."""
|
||||||
|
return _date_to_utc(self.data.get("dateModified")) # Folder does not have date
|
||||||
|
|
||||||
|
@property
|
||||||
|
def date_last_open(self):
|
||||||
|
"""Gets the node last open date (in UTC)."""
|
||||||
|
return _date_to_utc(self.data.get("lastOpenTime")) # Folder does not have date
|
||||||
|
|
||||||
|
def open(self, **kwargs):
|
||||||
|
"""Gets the node file."""
|
||||||
|
return self.connection.get_file(self.data["docwsid"], **kwargs)
|
||||||
|
|
||||||
|
def dir(self):
|
||||||
|
"""Gets the node list of directories."""
|
||||||
|
if self.type == "file":
|
||||||
|
return None
|
||||||
|
return [child.name for child in self.get_children()]
|
||||||
|
|
||||||
|
def get(self, name):
|
||||||
|
"""Gets the node child."""
|
||||||
|
if self.type == "file":
|
||||||
|
return None
|
||||||
|
return [child for child in self.get_children() if child.name == name][0]
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
try:
|
||||||
|
return self.get(key)
|
||||||
|
except IndexError:
|
||||||
|
raise KeyError("No child named '%s' exists" % key)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "{type: %s, name: %s}" % (self.type, self.name)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
as_unicode = self.__unicode__()
|
||||||
|
if PY2:
|
||||||
|
return as_unicode.encode("utf-8", "ignore")
|
||||||
|
return as_unicode
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s: %s>" % (type(self).__name__, str(self))
|
||||||
|
|
||||||
|
|
||||||
|
def _date_to_utc(date):
|
||||||
|
if not date:
|
||||||
|
return None
|
||||||
|
# jump through hoops to return time in UTC rather than California time
|
||||||
|
match = search(r"^(.+?)([\+\-]\d+):(\d\d)$", date)
|
||||||
|
if not match:
|
||||||
|
# Already in UTC
|
||||||
|
return datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
base = datetime.strptime(match.group(1), "%Y-%m-%dT%H:%M:%S")
|
||||||
|
diff = timedelta(hours=int(match.group(2)), minutes=int(match.group(3)))
|
||||||
|
return base - diff
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Library tests."""
|
"""Library tests."""
|
||||||
import json
|
import json
|
||||||
from requests import Session, Response
|
from requests import Session, Response
|
||||||
|
@ -22,16 +23,24 @@ from .const_login import (
|
||||||
)
|
)
|
||||||
from .const_account import ACCOUNT_DEVICES_WORKING, ACCOUNT_STORAGE_WORKING
|
from .const_account import ACCOUNT_DEVICES_WORKING, ACCOUNT_STORAGE_WORKING
|
||||||
from .const_account_family import ACCOUNT_FAMILY_WORKING
|
from .const_account_family import ACCOUNT_FAMILY_WORKING
|
||||||
|
from .const_drive import (
|
||||||
|
DRIVE_FOLDER_WORKING,
|
||||||
|
DRIVE_ROOT_INVALID,
|
||||||
|
DRIVE_SUBFOLDER_WORKING,
|
||||||
|
DRIVE_ROOT_WORKING,
|
||||||
|
DRIVE_FILE_DOWNLOAD_WORKING,
|
||||||
|
)
|
||||||
from .const_findmyiphone import FMI_FAMILY_WORKING
|
from .const_findmyiphone import FMI_FAMILY_WORKING
|
||||||
|
|
||||||
|
|
||||||
class ResponseMock(Response):
|
class ResponseMock(Response):
|
||||||
"""Mocked Response."""
|
"""Mocked Response."""
|
||||||
|
|
||||||
def __init__(self, result, status_code=200):
|
def __init__(self, result, status_code=200, **kwargs):
|
||||||
Response.__init__(self)
|
Response.__init__(self)
|
||||||
self.result = result
|
self.result = result
|
||||||
self.status_code = status_code
|
self.status_code = status_code
|
||||||
|
self.raw = kwargs.get("raw")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text(self):
|
def text(self):
|
||||||
|
@ -42,6 +51,7 @@ class PyiCloudSessionMock(base.PyiCloudSession):
|
||||||
"""Mocked PyiCloudSession."""
|
"""Mocked PyiCloudSession."""
|
||||||
|
|
||||||
def request(self, method, url, **kwargs):
|
def request(self, method, url, **kwargs):
|
||||||
|
params = kwargs.get("params")
|
||||||
data = json.loads(kwargs.get("data", "{}"))
|
data = json.loads(kwargs.get("data", "{}"))
|
||||||
|
|
||||||
# Login
|
# Login
|
||||||
|
@ -82,6 +92,34 @@ class PyiCloudSessionMock(base.PyiCloudSession):
|
||||||
if "setup/ws/1/storageUsageInfo" in url and method == "GET":
|
if "setup/ws/1/storageUsageInfo" in url and method == "GET":
|
||||||
return ResponseMock(ACCOUNT_STORAGE_WORKING)
|
return ResponseMock(ACCOUNT_STORAGE_WORKING)
|
||||||
|
|
||||||
|
# Drive
|
||||||
|
if (
|
||||||
|
"retrieveItemDetailsInFolders" in url
|
||||||
|
and method == "POST"
|
||||||
|
and data[0].get("drivewsid")
|
||||||
|
):
|
||||||
|
if data[0].get("drivewsid") == "FOLDER::com.apple.CloudDocs::root":
|
||||||
|
return ResponseMock(DRIVE_ROOT_WORKING)
|
||||||
|
if data[0].get("drivewsid") == "FOLDER::com.apple.CloudDocs::documents":
|
||||||
|
return ResponseMock(DRIVE_ROOT_INVALID)
|
||||||
|
if (
|
||||||
|
data[0].get("drivewsid")
|
||||||
|
== "FOLDER::com.apple.CloudDocs::1C7F1760-D940-480F-8C4F-005824A4E05B"
|
||||||
|
):
|
||||||
|
return ResponseMock(DRIVE_FOLDER_WORKING)
|
||||||
|
if (
|
||||||
|
data[0].get("drivewsid")
|
||||||
|
== "FOLDER::com.apple.CloudDocs::D5AA0425-E84F-4501-AF5D-60F1D92648CF"
|
||||||
|
):
|
||||||
|
return ResponseMock(DRIVE_SUBFOLDER_WORKING)
|
||||||
|
# Drive download
|
||||||
|
if "com.apple.CloudDocs/download/by_id" in url and method == "GET":
|
||||||
|
if params.get("document_id") == "516C896C-6AA5-4A30-B30E-5502C2333DAE":
|
||||||
|
return ResponseMock(DRIVE_FILE_DOWNLOAD_WORKING)
|
||||||
|
if "icloud-content.com" in url and method == "GET":
|
||||||
|
if "Scanned+document+1.pdf" in url:
|
||||||
|
return ResponseMock({}, raw=open(".gitignore", "rb"))
|
||||||
|
|
||||||
# Find My iPhone
|
# Find My iPhone
|
||||||
if "fmi" in url and method == "POST":
|
if "fmi" in url and method == "POST":
|
||||||
return ResponseMock(FMI_FAMILY_WORKING)
|
return ResponseMock(FMI_FAMILY_WORKING)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Test constants."""
|
"""Test constants."""
|
||||||
from .const_account_family import PRIMARY_EMAIL, APPLE_ID_EMAIL, ICLOUD_ID_EMAIL
|
from .const_account_family import PRIMARY_EMAIL, APPLE_ID_EMAIL, ICLOUD_ID_EMAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Account family test constants."""
|
"""Account family test constants."""
|
||||||
|
|
||||||
# Fakers
|
# Fakers
|
||||||
|
|
676
tests/const_drive.py
Normal file
676
tests/const_drive.py
Normal file
|
@ -0,0 +1,676 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Drive test constants."""
|
||||||
|
|
||||||
|
|
||||||
|
# Data
|
||||||
|
DRIVE_ROOT_WORKING = [
|
||||||
|
{
|
||||||
|
"drivewsid": "FOLDER::com.apple.CloudDocs::root",
|
||||||
|
"docwsid": "root",
|
||||||
|
"zone": "com.apple.CloudDocs",
|
||||||
|
"name": "",
|
||||||
|
"etag": "31",
|
||||||
|
"type": "FOLDER",
|
||||||
|
"assetQuota": 62418076,
|
||||||
|
"fileCount": 7,
|
||||||
|
"shareCount": 0,
|
||||||
|
"shareAliasCount": 0,
|
||||||
|
"directChildrenCount": 3,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"dateCreated": "2019-12-12T14:33:55-08:00",
|
||||||
|
"drivewsid": "FOLDER::com.apple.Keynote::documents",
|
||||||
|
"docwsid": "documents",
|
||||||
|
"zone": "com.apple.Keynote",
|
||||||
|
"name": "Keynote",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::root",
|
||||||
|
"etag": "2m",
|
||||||
|
"type": "APP_LIBRARY",
|
||||||
|
"maxDepth": "ANY",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Keynote&field=icon120x120_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Keynote&field=icon80x80_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Keynote&field=icon40x40_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 40,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"supportedExtensions": [
|
||||||
|
"pptx",
|
||||||
|
"ppsx",
|
||||||
|
"pps",
|
||||||
|
"pot",
|
||||||
|
"key-tef",
|
||||||
|
"ppt",
|
||||||
|
"potx",
|
||||||
|
"potm",
|
||||||
|
"pptm",
|
||||||
|
"ppsm",
|
||||||
|
"key",
|
||||||
|
"kth",
|
||||||
|
],
|
||||||
|
"supportedTypes": [
|
||||||
|
"com.microsoft.powerpoint.pps",
|
||||||
|
"com.microsoft.powerpoint.pot",
|
||||||
|
"com.microsoft.powerpoint.ppt",
|
||||||
|
"org.openxmlformats.presentationml.template.macroenabled",
|
||||||
|
"org.openxmlformats.presentationml.slideshow.macroenabled",
|
||||||
|
"com.apple.iwork.keynote.key-tef",
|
||||||
|
"org.openxmlformats.presentationml.template",
|
||||||
|
"org.openxmlformats.presentationml.presentation.macroenabled",
|
||||||
|
"com.apple.iwork.keynote.key",
|
||||||
|
"com.apple.iwork.keynote.kth",
|
||||||
|
"org.openxmlformats.presentationml.presentation",
|
||||||
|
"org.openxmlformats.presentationml.slideshow",
|
||||||
|
"com.apple.iwork.keynote.sffkey",
|
||||||
|
"com.apple.iwork.keynote.sffkth",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dateCreated": "2019-12-12T14:33:55-08:00",
|
||||||
|
"drivewsid": "FOLDER::com.apple.Numbers::documents",
|
||||||
|
"docwsid": "documents",
|
||||||
|
"zone": "com.apple.Numbers",
|
||||||
|
"name": "Numbers",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::root",
|
||||||
|
"etag": "3k",
|
||||||
|
"type": "APP_LIBRARY",
|
||||||
|
"maxDepth": "ANY",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Numbers&field=icon120x120_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Numbers&field=icon80x80_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Numbers&field=icon40x40_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 40,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"supportedExtensions": [
|
||||||
|
"hh",
|
||||||
|
"ksh",
|
||||||
|
"lm",
|
||||||
|
"xlt",
|
||||||
|
"c++",
|
||||||
|
"f95",
|
||||||
|
"lid",
|
||||||
|
"csv",
|
||||||
|
"numbers",
|
||||||
|
"php4",
|
||||||
|
"hp",
|
||||||
|
"py",
|
||||||
|
"nmbtemplate",
|
||||||
|
"lmm",
|
||||||
|
"jscript",
|
||||||
|
"php3",
|
||||||
|
"crash",
|
||||||
|
"patch",
|
||||||
|
"java",
|
||||||
|
"ym",
|
||||||
|
"xlam",
|
||||||
|
"text",
|
||||||
|
"mi",
|
||||||
|
"exp",
|
||||||
|
"adb",
|
||||||
|
"jav",
|
||||||
|
"ada",
|
||||||
|
"ii",
|
||||||
|
"defs",
|
||||||
|
"mm",
|
||||||
|
"cpp",
|
||||||
|
"cxx",
|
||||||
|
"pas",
|
||||||
|
"diff",
|
||||||
|
"pch++",
|
||||||
|
"javascript",
|
||||||
|
"panic",
|
||||||
|
"rb",
|
||||||
|
"ads",
|
||||||
|
"tcsh",
|
||||||
|
"ypp",
|
||||||
|
"yxx",
|
||||||
|
"ph3",
|
||||||
|
"ph4",
|
||||||
|
"phtml",
|
||||||
|
"xltx",
|
||||||
|
"hang",
|
||||||
|
"rbw",
|
||||||
|
"f77",
|
||||||
|
"for",
|
||||||
|
"js",
|
||||||
|
"h++",
|
||||||
|
"mig",
|
||||||
|
"gpurestart",
|
||||||
|
"mii",
|
||||||
|
"zsh",
|
||||||
|
"m3u",
|
||||||
|
"pch",
|
||||||
|
"sh",
|
||||||
|
"xltm",
|
||||||
|
"applescript",
|
||||||
|
"tsv",
|
||||||
|
"ymm",
|
||||||
|
"shutdownstall",
|
||||||
|
"cc",
|
||||||
|
"xlsx",
|
||||||
|
"scpt",
|
||||||
|
"c",
|
||||||
|
"inl",
|
||||||
|
"f",
|
||||||
|
"numbers-tef",
|
||||||
|
"h",
|
||||||
|
"i",
|
||||||
|
"hpp",
|
||||||
|
"hxx",
|
||||||
|
"dlyan",
|
||||||
|
"xla",
|
||||||
|
"l",
|
||||||
|
"cp",
|
||||||
|
"m",
|
||||||
|
"lpp",
|
||||||
|
"lxx",
|
||||||
|
"txt",
|
||||||
|
"r",
|
||||||
|
"s",
|
||||||
|
"xlsm",
|
||||||
|
"spin",
|
||||||
|
"php",
|
||||||
|
"csh",
|
||||||
|
"y",
|
||||||
|
"bash",
|
||||||
|
"m3u8",
|
||||||
|
"pl",
|
||||||
|
"f90",
|
||||||
|
"pm",
|
||||||
|
"xls",
|
||||||
|
],
|
||||||
|
"supportedTypes": [
|
||||||
|
"org.openxmlformats.spreadsheetml.sheet",
|
||||||
|
"com.microsoft.excel.xla",
|
||||||
|
"com.apple.iwork.numbers.template",
|
||||||
|
"org.openxmlformats.spreadsheetml.sheet.macroenabled",
|
||||||
|
"com.apple.iwork.numbers.sffnumbers",
|
||||||
|
"com.apple.iwork.numbers.numbers",
|
||||||
|
"public.plain-text",
|
||||||
|
"com.microsoft.excel.xlt",
|
||||||
|
"org.openxmlformats.spreadsheetml.template",
|
||||||
|
"com.microsoft.excel.xls",
|
||||||
|
"public.comma-separated-values-text",
|
||||||
|
"com.apple.iwork.numbers.numbers-tef",
|
||||||
|
"org.openxmlformats.spreadsheetml.template.macroenabled",
|
||||||
|
"public.tab-separated-values-text",
|
||||||
|
"com.apple.iwork.numbers.sfftemplate",
|
||||||
|
"com.microsoft.excel.openxml.addin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dateCreated": "2019-12-12T14:33:55-08:00",
|
||||||
|
"drivewsid": "FOLDER::com.apple.Pages::documents",
|
||||||
|
"docwsid": "documents",
|
||||||
|
"zone": "com.apple.Pages",
|
||||||
|
"name": "Pages",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::root",
|
||||||
|
"etag": "km",
|
||||||
|
"type": "APP_LIBRARY",
|
||||||
|
"maxDepth": "ANY",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Pages&field=icon120x120_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Pages&field=icon80x80_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Pages&field=icon40x40_iOS",
|
||||||
|
"type": "IOS",
|
||||||
|
"size": 40,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"supportedExtensions": [
|
||||||
|
"hh",
|
||||||
|
"ksh",
|
||||||
|
"lm",
|
||||||
|
"c++",
|
||||||
|
"f95",
|
||||||
|
"lid",
|
||||||
|
"php4",
|
||||||
|
"hp",
|
||||||
|
"py",
|
||||||
|
"lmm",
|
||||||
|
"jscript",
|
||||||
|
"php3",
|
||||||
|
"crash",
|
||||||
|
"patch",
|
||||||
|
"pages",
|
||||||
|
"java",
|
||||||
|
"ym",
|
||||||
|
"text",
|
||||||
|
"mi",
|
||||||
|
"exp",
|
||||||
|
"adb",
|
||||||
|
"jav",
|
||||||
|
"ada",
|
||||||
|
"ii",
|
||||||
|
"defs",
|
||||||
|
"mm",
|
||||||
|
"cpp",
|
||||||
|
"cxx",
|
||||||
|
"pas",
|
||||||
|
"pages-tef",
|
||||||
|
"diff",
|
||||||
|
"pch++",
|
||||||
|
"javascript",
|
||||||
|
"panic",
|
||||||
|
"rb",
|
||||||
|
"ads",
|
||||||
|
"tcsh",
|
||||||
|
"rtfd",
|
||||||
|
"ypp",
|
||||||
|
"yxx",
|
||||||
|
"doc",
|
||||||
|
"ph3",
|
||||||
|
"ph4",
|
||||||
|
"template",
|
||||||
|
"phtml",
|
||||||
|
"hang",
|
||||||
|
"rbw",
|
||||||
|
"f77",
|
||||||
|
"dot",
|
||||||
|
"for",
|
||||||
|
"js",
|
||||||
|
"h++",
|
||||||
|
"mig",
|
||||||
|
"gpurestart",
|
||||||
|
"mii",
|
||||||
|
"zsh",
|
||||||
|
"m3u",
|
||||||
|
"pch",
|
||||||
|
"sh",
|
||||||
|
"applescript",
|
||||||
|
"ymm",
|
||||||
|
"shutdownstall",
|
||||||
|
"dotx",
|
||||||
|
"cc",
|
||||||
|
"scpt",
|
||||||
|
"c",
|
||||||
|
"rtf",
|
||||||
|
"inl",
|
||||||
|
"f",
|
||||||
|
"h",
|
||||||
|
"i",
|
||||||
|
"hpp",
|
||||||
|
"hxx",
|
||||||
|
"dlyan",
|
||||||
|
"l",
|
||||||
|
"cp",
|
||||||
|
"m",
|
||||||
|
"lpp",
|
||||||
|
"lxx",
|
||||||
|
"docx",
|
||||||
|
"txt",
|
||||||
|
"r",
|
||||||
|
"s",
|
||||||
|
"spin",
|
||||||
|
"php",
|
||||||
|
"csh",
|
||||||
|
"y",
|
||||||
|
"bash",
|
||||||
|
"m3u8",
|
||||||
|
"pl",
|
||||||
|
"f90",
|
||||||
|
"pm",
|
||||||
|
],
|
||||||
|
"supportedTypes": [
|
||||||
|
"com.apple.rtfd",
|
||||||
|
"com.apple.iwork.pages.sffpages",
|
||||||
|
"com.apple.iwork.pages.sfftemplate",
|
||||||
|
"com.microsoft.word.dot",
|
||||||
|
"com.apple.iwork.pages.pages",
|
||||||
|
"com.microsoft.word.doc",
|
||||||
|
"org.openxmlformats.wordprocessingml.template",
|
||||||
|
"org.openxmlformats.wordprocessingml.document",
|
||||||
|
"com.apple.iwork.pages.pages-tef",
|
||||||
|
"com.apple.iwork.pages.template",
|
||||||
|
"public.rtf",
|
||||||
|
"public.plain-text",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dateCreated": "2019-12-12T14:33:55-08:00",
|
||||||
|
"drivewsid": "FOLDER::com.apple.Preview::documents",
|
||||||
|
"docwsid": "documents",
|
||||||
|
"zone": "com.apple.Preview",
|
||||||
|
"name": "Preview",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::root",
|
||||||
|
"etag": "bv",
|
||||||
|
"type": "APP_LIBRARY",
|
||||||
|
"maxDepth": "ANY",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Preview&field=icon32x32_OSX",
|
||||||
|
"type": "OSX",
|
||||||
|
"size": 32,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Preview&field=icon128x128_OSX",
|
||||||
|
"type": "OSX",
|
||||||
|
"size": 128,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Preview&field=icon16x16_OSX",
|
||||||
|
"type": "OSX",
|
||||||
|
"size": 16,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Preview&field=icon256x256_OSX",
|
||||||
|
"type": "OSX",
|
||||||
|
"size": 256,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://p31-drivews.icloud.com/getIcons?id=com.apple.Preview&field=icon64x64_OSX",
|
||||||
|
"type": "OSX",
|
||||||
|
"size": 64,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"supportedExtensions": [
|
||||||
|
"ps",
|
||||||
|
"nmbtemplate",
|
||||||
|
"astc",
|
||||||
|
"mpkg",
|
||||||
|
"prefpane",
|
||||||
|
"pef",
|
||||||
|
"mos",
|
||||||
|
"qlgenerator",
|
||||||
|
"scptd",
|
||||||
|
"raf",
|
||||||
|
"saver",
|
||||||
|
"band",
|
||||||
|
"dng",
|
||||||
|
"pict",
|
||||||
|
"exr",
|
||||||
|
"kth",
|
||||||
|
"appex",
|
||||||
|
"app",
|
||||||
|
"pages-tef",
|
||||||
|
"slidesaver",
|
||||||
|
"pluginkit",
|
||||||
|
"distz",
|
||||||
|
"ai",
|
||||||
|
"png",
|
||||||
|
"eps",
|
||||||
|
"raw",
|
||||||
|
"pvr",
|
||||||
|
"mpo",
|
||||||
|
"ktx",
|
||||||
|
"nrw",
|
||||||
|
"lpdf",
|
||||||
|
"pfm",
|
||||||
|
"3fr",
|
||||||
|
"template",
|
||||||
|
"imovielibrary",
|
||||||
|
"pwl",
|
||||||
|
"iwwebpackage",
|
||||||
|
"wdgt",
|
||||||
|
"tga",
|
||||||
|
"pgm",
|
||||||
|
"erf",
|
||||||
|
"jpeg",
|
||||||
|
"j2c",
|
||||||
|
"bundle",
|
||||||
|
"key",
|
||||||
|
"j2k",
|
||||||
|
"abc",
|
||||||
|
"arw",
|
||||||
|
"xpc",
|
||||||
|
"pic",
|
||||||
|
"ppm",
|
||||||
|
"menu",
|
||||||
|
"icns",
|
||||||
|
"mrw",
|
||||||
|
"plugin",
|
||||||
|
"mdimporter",
|
||||||
|
"bmp",
|
||||||
|
"numbers",
|
||||||
|
"dae",
|
||||||
|
"dist",
|
||||||
|
"pic",
|
||||||
|
"rw2",
|
||||||
|
"nef",
|
||||||
|
"tif",
|
||||||
|
"pages",
|
||||||
|
"sgi",
|
||||||
|
"ico",
|
||||||
|
"theater",
|
||||||
|
"gbproj",
|
||||||
|
"webplugin",
|
||||||
|
"cr2",
|
||||||
|
"fff",
|
||||||
|
"webp",
|
||||||
|
"jp2",
|
||||||
|
"sr2",
|
||||||
|
"rtfd",
|
||||||
|
"pbm",
|
||||||
|
"pkpass",
|
||||||
|
"jfx",
|
||||||
|
"fpbf",
|
||||||
|
"psd",
|
||||||
|
"xbm",
|
||||||
|
"tiff",
|
||||||
|
"avchd",
|
||||||
|
"gif",
|
||||||
|
"pntg",
|
||||||
|
"rwl",
|
||||||
|
"pset",
|
||||||
|
"pkg",
|
||||||
|
"dcr",
|
||||||
|
"hdr",
|
||||||
|
"jpe",
|
||||||
|
"pct",
|
||||||
|
"jpg",
|
||||||
|
"jpf",
|
||||||
|
"orf",
|
||||||
|
"srf",
|
||||||
|
"numbers-tef",
|
||||||
|
"iconset",
|
||||||
|
"crw",
|
||||||
|
"fpx",
|
||||||
|
"dds",
|
||||||
|
"pdf",
|
||||||
|
"jpx",
|
||||||
|
"key-tef",
|
||||||
|
"efx",
|
||||||
|
"hdr",
|
||||||
|
"srw",
|
||||||
|
],
|
||||||
|
"supportedTypes": [
|
||||||
|
"com.adobe.illustrator.ai-image",
|
||||||
|
"com.kodak.flashpix-image",
|
||||||
|
"public.pbm",
|
||||||
|
"com.apple.pict",
|
||||||
|
"com.ilm.openexr-image",
|
||||||
|
"com.sgi.sgi-image",
|
||||||
|
"com.apple.icns",
|
||||||
|
"public.heifs",
|
||||||
|
"com.truevision.tga-image",
|
||||||
|
"com.adobe.postscript",
|
||||||
|
"public.camera-raw-image",
|
||||||
|
"public.pvr",
|
||||||
|
"public.png",
|
||||||
|
"com.adobe.photoshop-image",
|
||||||
|
"public.heif",
|
||||||
|
"com.microsoft.ico",
|
||||||
|
"com.adobe.pdf",
|
||||||
|
"public.heic",
|
||||||
|
"public.xbitmap-image",
|
||||||
|
"com.apple.localized-pdf-bundle",
|
||||||
|
"public.3d-content",
|
||||||
|
"com.compuserve.gif",
|
||||||
|
"public.avci",
|
||||||
|
"public.jpeg",
|
||||||
|
"com.apple.rjpeg",
|
||||||
|
"com.adobe.encapsulated-postscript",
|
||||||
|
"com.microsoft.bmp",
|
||||||
|
"public.fax",
|
||||||
|
"org.khronos.astc",
|
||||||
|
"com.apple.application-bundle",
|
||||||
|
"public.avcs",
|
||||||
|
"public.webp",
|
||||||
|
"public.heics",
|
||||||
|
"com.apple.macpaint-image",
|
||||||
|
"public.mpo-image",
|
||||||
|
"public.jpeg-2000",
|
||||||
|
"public.tiff",
|
||||||
|
"com.microsoft.dds",
|
||||||
|
"com.apple.pdf-printer-settings",
|
||||||
|
"org.khronos.ktx",
|
||||||
|
"public.radiance",
|
||||||
|
"com.apple.package",
|
||||||
|
"public.folder",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"drivewsid": "FOLDER::com.apple.CloudDocs::1C7F1760-D940-480F-8C4F-005824A4E05B",
|
||||||
|
"docwsid": "1C7F1760-D940-480F-8C4F-005824A4E05B",
|
||||||
|
"zone": "com.apple.CloudDocs",
|
||||||
|
"name": "pyiCloud",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::root",
|
||||||
|
"etag": "30",
|
||||||
|
"type": "FOLDER",
|
||||||
|
"assetQuota": 42199575,
|
||||||
|
"fileCount": 2,
|
||||||
|
"shareCount": 0,
|
||||||
|
"shareAliasCount": 0,
|
||||||
|
"directChildrenCount": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"numberOfItems": 5,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# App specific folder (Keynote, Numbers, Pages, Preview ...) type=APP_LIBRARY
|
||||||
|
DRIVE_ROOT_INVALID = [
|
||||||
|
{"drivewsid": "FOLDER::com.apple.CloudDocs::documents", "status": "ID_INVALID"}
|
||||||
|
]
|
||||||
|
|
||||||
|
DRIVE_FOLDER_WORKING = [
|
||||||
|
{
|
||||||
|
"drivewsid": "FOLDER::com.apple.CloudDocs::1C7F1760-D940-480F-8C4F-005824A4E05B",
|
||||||
|
"docwsid": "1C7F1760-D940-480F-8C4F-005824A4E05B",
|
||||||
|
"zone": "com.apple.CloudDocs",
|
||||||
|
"name": "pyiCloud",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::root",
|
||||||
|
"etag": "30",
|
||||||
|
"type": "FOLDER",
|
||||||
|
"assetQuota": 42199575,
|
||||||
|
"fileCount": 2,
|
||||||
|
"shareCount": 0,
|
||||||
|
"shareAliasCount": 0,
|
||||||
|
"directChildrenCount": 1,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"drivewsid": "FOLDER::com.apple.CloudDocs::D5AA0425-E84F-4501-AF5D-60F1D92648CF",
|
||||||
|
"docwsid": "D5AA0425-E84F-4501-AF5D-60F1D92648CF",
|
||||||
|
"zone": "com.apple.CloudDocs",
|
||||||
|
"name": "Test",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::1C7F1760-D940-480F-8C4F-005824A4E05B",
|
||||||
|
"etag": "2z",
|
||||||
|
"type": "FOLDER",
|
||||||
|
"assetQuota": 42199575,
|
||||||
|
"fileCount": 2,
|
||||||
|
"shareCount": 0,
|
||||||
|
"shareAliasCount": 0,
|
||||||
|
"directChildrenCount": 2,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"numberOfItems": 1,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
DRIVE_SUBFOLDER_WORKING = [
|
||||||
|
{
|
||||||
|
"drivewsid": "FOLDER::com.apple.CloudDocs::D5AA0425-E84F-4501-AF5D-60F1D92648CF",
|
||||||
|
"docwsid": "D5AA0425-E84F-4501-AF5D-60F1D92648CF",
|
||||||
|
"zone": "com.apple.CloudDocs",
|
||||||
|
"name": "Test",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::1C7F1760-D940-480F-8C4F-005824A4E05B",
|
||||||
|
"etag": "2z",
|
||||||
|
"type": "FOLDER",
|
||||||
|
"assetQuota": 42199575,
|
||||||
|
"fileCount": 2,
|
||||||
|
"shareCount": 0,
|
||||||
|
"shareAliasCount": 0,
|
||||||
|
"directChildrenCount": 2,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"drivewsid": "FILE::com.apple.CloudDocs::33A41112-4131-4938-9691-7F356CE3C51D",
|
||||||
|
"docwsid": "33A41112-4131-4938-9691-7F356CE3C51D",
|
||||||
|
"zone": "com.apple.CloudDocs",
|
||||||
|
"name": "Document scanné 2",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::D5AA0425-E84F-4501-AF5D-60F1D92648CF",
|
||||||
|
"dateModified": "2020-04-27T21:37:36Z",
|
||||||
|
"dateChanged": "2020-04-27T14:44:29-07:00",
|
||||||
|
"size": 19876991,
|
||||||
|
"etag": "2k::2j",
|
||||||
|
"extension": "pdf",
|
||||||
|
"hiddenExtension": True,
|
||||||
|
"lastOpenTime": "2020-04-27T21:37:36Z",
|
||||||
|
"type": "FILE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"drivewsid": "FILE::com.apple.CloudDocs::516C896C-6AA5-4A30-B30E-5502C2333DAE",
|
||||||
|
"docwsid": "516C896C-6AA5-4A30-B30E-5502C2333DAE",
|
||||||
|
"zone": "com.apple.CloudDocs",
|
||||||
|
"name": "Scanned document 1",
|
||||||
|
"parentId": "FOLDER::com.apple.CloudDocs::D5AA0425-E84F-4501-AF5D-60F1D92648CF",
|
||||||
|
"dateModified": "2020-05-03T00:15:17Z",
|
||||||
|
"dateChanged": "2020-05-02T17:16:17-07:00",
|
||||||
|
"size": 21644358,
|
||||||
|
"etag": "32::2x",
|
||||||
|
"extension": "pdf",
|
||||||
|
"hiddenExtension": True,
|
||||||
|
"lastOpenTime": "2020-05-03T00:24:25Z",
|
||||||
|
"type": "FILE",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"numberOfItems": 2,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
DRIVE_FILE_DOWNLOAD_WORKING = {
|
||||||
|
"document_id": "516C896C-6AA5-4A30-B30E-5502C2333DAE",
|
||||||
|
"data_token": {
|
||||||
|
"url": "https://cvws.icloud-content.com/B/signature1ref_signature1/Scanned+document+1.pdf?o=object1&v=1&x=3&a=token1&e=1588472097&k=wrapping_key1&fl=&r=request&ckc=com.apple.clouddocs&ckz=com.apple.CloudDocs&p=31&s=s1",
|
||||||
|
"token": "token1",
|
||||||
|
"signature": "signature1",
|
||||||
|
"wrapping_key": "wrapping_key1==",
|
||||||
|
"reference_signature": "ref_signature1",
|
||||||
|
},
|
||||||
|
"thumbnail_token": {
|
||||||
|
"url": "https://cvws.icloud-content.com/B/signature2ref_signature2/Scanned+document+1.jpg?o=object2&v=1&x=3&a=token2&e=1588472097&k=wrapping_key2&fl=&r=request&ckc=com.apple.clouddocs&ckz=com.apple.CloudDocs&p=31&s=s2",
|
||||||
|
"token": "token2",
|
||||||
|
"signature": "signature2",
|
||||||
|
"wrapping_key": "wrapping_key2==",
|
||||||
|
"reference_signature": "ref_signature2",
|
||||||
|
},
|
||||||
|
"double_etag": "32::2x",
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Find my iPhone test constants."""
|
"""Find my iPhone test constants."""
|
||||||
from .const import CLIENT_ID
|
from .const import CLIENT_ID
|
||||||
from .const_account_family import (
|
from .const_account_family import (
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Login test constants."""
|
"""Login test constants."""
|
||||||
from .const_account_family import (
|
from .const_account_family import (
|
||||||
FIRST_NAME,
|
FIRST_NAME,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Account service tests."""
|
"""Account service tests."""
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from six import PY3
|
from six import PY3
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Cmdline tests."""
|
"""Cmdline tests."""
|
||||||
from pyicloud import cmdline
|
from pyicloud import cmdline
|
||||||
from . import PyiCloudServiceMock
|
from . import PyiCloudServiceMock
|
||||||
|
|
83
tests/test_drive.py
Normal file
83
tests/test_drive.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Drive service tests."""
|
||||||
|
from unittest import TestCase
|
||||||
|
from . import PyiCloudServiceMock
|
||||||
|
from .const import AUTHENTICATED_USER, VALID_PASSWORD
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
# pylint: disable=pointless-statement
|
||||||
|
class DriveServiceTest(TestCase):
|
||||||
|
""""Drive service tests"""
|
||||||
|
|
||||||
|
service = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.service = PyiCloudServiceMock(AUTHENTICATED_USER, VALID_PASSWORD)
|
||||||
|
|
||||||
|
def test_root(self):
|
||||||
|
"""Test the root folder."""
|
||||||
|
drive = self.service.drive
|
||||||
|
assert drive.name == ""
|
||||||
|
assert drive.type == "folder"
|
||||||
|
assert drive.size is None
|
||||||
|
assert drive.date_changed is None
|
||||||
|
assert drive.date_modified is None
|
||||||
|
assert drive.date_last_open is None
|
||||||
|
assert drive.dir() == ["Keynote", "Numbers", "Pages", "Preview", "pyiCloud"]
|
||||||
|
|
||||||
|
def test_folder_app(self):
|
||||||
|
"""Test the /Preview folder."""
|
||||||
|
folder = self.service.drive["Preview"]
|
||||||
|
assert folder.name == "Preview"
|
||||||
|
assert folder.type == "app_library"
|
||||||
|
assert folder.size is None
|
||||||
|
assert folder.date_changed is None
|
||||||
|
assert folder.date_modified is None
|
||||||
|
assert folder.date_last_open is None
|
||||||
|
with pytest.raises(KeyError, match="No items in folder, status: ID_INVALID"):
|
||||||
|
assert folder.dir()
|
||||||
|
|
||||||
|
def test_folder_not_exists(self):
|
||||||
|
"""Test the /not_exists folder."""
|
||||||
|
with pytest.raises(KeyError, match="No child named 'not_exists' exists"):
|
||||||
|
self.service.drive["not_exists"]
|
||||||
|
|
||||||
|
def test_folder(self):
|
||||||
|
"""Test the /pyiCloud folder."""
|
||||||
|
folder = self.service.drive["pyiCloud"]
|
||||||
|
assert folder.name == "pyiCloud"
|
||||||
|
assert folder.type == "folder"
|
||||||
|
assert folder.size is None
|
||||||
|
assert folder.date_changed is None
|
||||||
|
assert folder.date_modified is None
|
||||||
|
assert folder.date_last_open is None
|
||||||
|
assert folder.dir() == ["Test"]
|
||||||
|
|
||||||
|
def test_subfolder(self):
|
||||||
|
"""Test the /pyiCloud/Test folder."""
|
||||||
|
folder = self.service.drive["pyiCloud"]["Test"]
|
||||||
|
assert folder.name == "Test"
|
||||||
|
assert folder.type == "folder"
|
||||||
|
assert folder.size is None
|
||||||
|
assert folder.date_changed is None
|
||||||
|
assert folder.date_modified is None
|
||||||
|
assert folder.date_last_open is None
|
||||||
|
assert folder.dir() == [u"Document scanné 2.pdf", "Scanned document 1.pdf"]
|
||||||
|
|
||||||
|
def test_subfolder_file(self):
|
||||||
|
"""Test the /pyiCloud/Test/Scanned document 1.pdf file."""
|
||||||
|
folder = self.service.drive["pyiCloud"]["Test"]
|
||||||
|
file_test = folder["Scanned document 1.pdf"]
|
||||||
|
assert file_test.name == "Scanned document 1.pdf"
|
||||||
|
assert file_test.type == "file"
|
||||||
|
assert file_test.size == 21644358
|
||||||
|
assert str(file_test.date_changed) == "2020-05-03 00:16:17"
|
||||||
|
assert str(file_test.date_modified) == "2020-05-03 00:15:17"
|
||||||
|
assert str(file_test.date_last_open) == "2020-05-03 00:24:25"
|
||||||
|
assert file_test.dir() is None
|
||||||
|
|
||||||
|
def test_file_open(self):
|
||||||
|
"""Test the /pyiCloud/Test/Scanned document 1.pdf file open."""
|
||||||
|
file_test = self.service.drive["pyiCloud"]["Test"]["Scanned document 1.pdf"]
|
||||||
|
with file_test.open(stream=True) as response:
|
||||||
|
assert response.raw
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""Find My iPhone service tests."""
|
"""Find My iPhone service tests."""
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from . import PyiCloudServiceMock
|
from . import PyiCloudServiceMock
|
||||||
|
|
Loading…
Reference in a new issue