Skip to content

Commit 8ebf15b

Browse files
authored
Saimon/improved file browsing exception handling (#324)
1 parent 17e424a commit 8ebf15b

File tree

34 files changed

+2287
-1647
lines changed

34 files changed

+2287
-1647
lines changed

cterasdk/asynchronous/core/files/browser.py

Lines changed: 78 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from ....cio.core import CorePath, a_await_or_future
2-
from ....lib.storage import asynfs, commonfs
3-
from ....exceptions.io import FileConflict
1+
from .. import query
2+
from ....cio.core import CorePath, Open, OpenMany, Upload, UploadFile, Download, \
3+
DownloadMany, UnShare, CreateDirectory, GetMetadata, ListVersions, RecursiveIterator, \
4+
Delete, Recover, Rename, GetShareMetadata, Link, Copy, Move, ResourceIterator, GetPermalink
45
from ..base_command import BaseCommand
56
from . import io
67

@@ -17,8 +18,7 @@ async def handle(self, path):
1718
1819
:param str path: Path to a file
1920
"""
20-
handle_function = io.handle(self.normalize(path))
21-
return await handle_function(self._core)
21+
return await Open(io.handle, self._core, self.normalize(path)).a_execute()
2222

2323
async def handle_many(self, directory, *objects):
2424
"""
@@ -27,8 +27,7 @@ async def handle_many(self, directory, *objects):
2727
:param str directory: Path to a folder
2828
:param args objects: List of files and folders
2929
"""
30-
handle_many_function = io.handle_many(self.normalize(directory), *objects)
31-
return await handle_many_function(self._core)
30+
return await OpenMany(io.handle_many, self._core, self.normalize(directory), *objects).a_execute()
3231

3332
async def download(self, path, destination=None):
3433
"""
@@ -38,9 +37,7 @@ async def download(self, path, destination=None):
3837
:param str,optional destination:
3938
File destination, if it is a directory, the original filename will be kept, defaults to the default directory
4039
"""
41-
directory, name = commonfs.determine_directory_and_filename(path, destination=destination)
42-
handle = await self.handle(path)
43-
return await asynfs.write(directory, name, handle)
40+
return await Download(io.handle, self._core, self.normalize(path), destination).a_execute()
4441

4542
async def download_many(self, target, objects, destination=None):
4643
"""
@@ -58,9 +55,7 @@ async def download_many(self, target, objects, destination=None):
5855
Optional. Path to the destination file or directory. If a directory is provided,
5956
the original filename will be preserved. Defaults to the default download directory.
6057
"""
61-
directory, name = commonfs.determine_directory_and_filename(target, objects, destination=destination, archive=True)
62-
handle = await self.handle_many(target, *objects)
63-
return await asynfs.write(directory, name, handle)
58+
return await DownloadMany(io.handle_many, self._core, self.normalize(target), objects, destination).a_execute()
6459

6560
async def listdir(self, path=None, depth=None, include_deleted=False):
6661
"""
@@ -69,23 +64,25 @@ async def listdir(self, path=None, depth=None, include_deleted=False):
6964
:param str,optional path: Path, defaults to the Cloud Drive root
7065
:param bool,optional include_deleted: Include deleted files, defaults to False
7166
"""
72-
return await io.listdir(self._core, self.normalize(path), depth=depth, include_deleted=include_deleted)
67+
async for o in ResourceIterator(query.iterator, self._core, self.normalize(path), depth, include_deleted, None, None).a_execute():
68+
yield o
7369

7470
async def exists(self, path):
7571
"""
7672
Check if item exists
7773
7874
:param str path: Path
7975
"""
80-
return await io.exists(self._core, self.normalize(path))
76+
async with GetMetadata(io.listdir, self._core, self.normalize(path), True) as (exists, *_):
77+
return exists
8178

8279
async def versions(self, path):
8380
"""
8481
List snapshots of a file or directory
8582
8683
:param str path: Path
8784
"""
88-
return await io.versions(self._core, self.normalize(path))
85+
return await ListVersions(io.versions, self._core, self.normalize(path)).a_execute()
8986

9087
async def walk(self, path=None, include_deleted=False):
9188
"""
@@ -94,7 +91,8 @@ async def walk(self, path=None, include_deleted=False):
9491
:param str,optional path: Path to walk, defaults to the root directory
9592
:param bool,optional include_deleted: Include deleted files, defaults to False
9693
"""
97-
return io.walk(self._core, self._scope, path, include_deleted=include_deleted)
94+
async for o in RecursiveIterator(query.iterator, self._core, self.normalize(path), include_deleted).a_generate():
95+
yield o
9896

9997
async def public_link(self, path, access='RO', expire_in=30):
10098
"""
@@ -104,19 +102,7 @@ async def public_link(self, path, access='RO', expire_in=30):
104102
:param str,optional access: Access policy of the link, defaults to 'RO'
105103
:param int,optional expire_in: Number of days until the link expires, defaults to 30
106104
"""
107-
return await io.public_link(self._core, self.normalize(path), access, expire_in)
108-
109-
async def _try_with_resolver(self, func, *paths, destination=None, resolver=None, cursor=None, wait=False):
110-
async def wrapper(resume_from=None):
111-
ref = await func(self._core, *paths, destination=destination, resolver=resolver, cursor=resume_from)
112-
return await a_await_or_future(self._core, ref, wait)
113-
114-
try:
115-
return await wrapper(cursor)
116-
except FileConflict as e:
117-
if resolver:
118-
return await wrapper(e.cursor)
119-
raise
105+
return await Link(io.public_link, self._core, self.normalize(path), access, expire_in).a_execute()
120106

121107
async def copy(self, *paths, destination=None, resolver=None, cursor=None, wait=False):
122108
"""
@@ -131,9 +117,8 @@ async def copy(self, *paths, destination=None, resolver=None, cursor=None, wait=
131117
:rtype: cterasdk.common.object.Object or :class:`cterasdk.lib.tasks.AwaitablePortalTask`
132118
"""
133119
try:
134-
return await self._try_with_resolver(io.copy, *[self.normalize(path) for path in paths],
135-
destination=self.normalize(destination),
136-
resolver=resolver, cursor=cursor, wait=wait)
120+
return await Copy(io.copy, self._core, wait, *[self.normalize(path) for path in paths],
121+
destination=self.normalize(destination), resolver=resolver, cursor=cursor).a_execute()
137122
except ValueError:
138123
raise ValueError('Copy destination was not specified.')
139124

@@ -143,11 +128,7 @@ async def permalink(self, path):
143128
144129
:param str path: Path.
145130
"""
146-
p = self.normalize(path)
147-
async for e in await io.listdir(self._core, p.parent, 1, False, p.name, 1):
148-
if e.name == p.name:
149-
return e.permalink
150-
raise FileNotFoundError('File not found.', path)
131+
return await GetPermalink(io.listdir, self._core, self.normalize(path)).a_execute()
151132

152133
def normalize(self, entries):
153134
return CorePath.instance(self._scope, entries)
@@ -164,8 +145,7 @@ async def upload(self, name, destination, handle, size=None):
164145
:param object handle: Handle.
165146
:param str,optional size: File size, defaults to content length
166147
"""
167-
upload_function = io.upload(name, size, self.normalize(destination), handle)
168-
return await upload_function(self._core)
148+
return await Upload(io.upload, self._core, io.listdir, name, self.normalize(destination), size, handle).a_execute()
169149

170150
async def upload_file(self, path, destination):
171151
"""
@@ -174,26 +154,23 @@ async def upload_file(self, path, destination):
174154
:param str path: Local path
175155
:param str destination: Remote path
176156
"""
177-
with open(path, 'rb') as handle:
178-
metadata = commonfs.properties(path)
179-
response = await self.upload(metadata['name'], destination, handle, metadata['size'])
180-
return response
157+
return await UploadFile(io.upload, self._core, io.listdir, path, self.normalize(destination)).a_execute()
181158

182159
async def mkdir(self, path):
183160
"""
184161
Create a new directory
185162
186163
:param str path: Directory path
187164
"""
188-
return await io.mkdir(self._core, self.normalize(path))
165+
return await CreateDirectory(io.mkdir, self._core, self.normalize(path)).a_execute()
189166

190167
async def makedirs(self, path):
191168
"""
192169
Create a directory recursively
193170
194171
:param str path: Directory path
195172
"""
196-
return await io.makedirs(self._core, self.normalize(path))
173+
return await CreateDirectory(io.mkdir, self._core, self.normalize(path), True).a_execute()
197174

198175
async def rename(self, path, name, *, wait=False):
199176
"""
@@ -205,8 +182,7 @@ async def rename(self, path, name, *, wait=False):
205182
:returns: Task status object, or an awaitable task object
206183
:rtype: cterasdk.common.object.Object or :class:`cterasdk.lib.tasks.AwaitablePortalTask`
207184
"""
208-
ref = await io.rename(self._core, self.normalize(path), name)
209-
return await a_await_or_future(self._core, ref, wait)
185+
return await Rename(io.move, self._core, self.normalize(path), name, wait).a_execute()
210186

211187
async def delete(self, *paths, wait=False):
212188
"""
@@ -217,8 +193,7 @@ async def delete(self, *paths, wait=False):
217193
:returns: Task status object, or an awaitable task object
218194
:rtype: cterasdk.common.object.Object or :class:`cterasdk.lib.tasks.AwaitablePortalTask`
219195
"""
220-
ref = await io.remove(self._core, *[self.normalize(path) for path in paths])
221-
return await a_await_or_future(self._core, ref, wait)
196+
return await Delete(io.delete, self._core, wait, *[self.normalize(path) for path in paths]).a_execute()
222197

223198
async def undelete(self, *paths, wait=False):
224199
"""
@@ -229,8 +204,7 @@ async def undelete(self, *paths, wait=False):
229204
:returns: Task status object, or an awaitable task object
230205
:rtype: cterasdk.common.object.Object or :class:`cterasdk.lib.tasks.AwaitablePortalTask`
231206
"""
232-
ref = await io.recover(self._core, *[self.normalize(path) for path in paths])
233-
return await a_await_or_future(self._core, ref, wait)
207+
return await Recover(io.undelete, self._core, wait, *[self.normalize(path) for path in paths]).a_execute()
234208

235209
async def move(self, *paths, destination=None, resolver=None, cursor=None, wait=False):
236210
"""
@@ -245,8 +219,57 @@ async def move(self, *paths, destination=None, resolver=None, cursor=None, wait=
245219
:rtype: cterasdk.common.object.Object or :class:`cterasdk.lib.tasks.AwaitablePortalTask`
246220
"""
247221
try:
248-
return await self._try_with_resolver(io.move, *[self.normalize(path) for path in paths],
249-
destination=self.normalize(destination),
250-
resolver=resolver, cursor=cursor, wait=wait)
222+
return await Move(io.move, self._core, wait, *[self.normalize(path) for path in paths],
223+
destination=self.normalize(destination), resolver=resolver, cursor=cursor).a_execute()
251224
except ValueError:
252225
raise ValueError('Move destination was not specified.')
226+
227+
async def get_share_info(self, path):
228+
"""
229+
Get share settings and recipients
230+
231+
:param str path: Path
232+
"""
233+
return await GetShareMetadata(io.list_shares, self._core, self.normalize(path)).a_execute()
234+
235+
async def share(self, path, recipients, as_project=True, allow_reshare=True, allow_sync=True):
236+
"""
237+
Share a file or a folder
238+
239+
:param str path: The path of the file or folder to share
240+
:param list[cterasdk.core.types.Collaborator] recipients: A list of share recipients
241+
:param bool,optional as_project: Share as a team project, defaults to True when the item is a cloud folder else False
242+
:param bool,optional allow_reshare: Allow recipients to re-share this item, defaults to True
243+
:param bool,optional allow_sync: Allow recipients to sync this item, defaults to True when the item is a cloud folder else False
244+
:return: A list of all recipients added to the collaboration share
245+
:rtype: list[cterasdk.core.types.Collaborator]
246+
"""
247+
return await io.share(self._core, self.normalize(path), recipients, as_project, allow_reshare, allow_sync)
248+
249+
async def add_share_recipients(self, path, recipients):
250+
"""
251+
Add share recipients
252+
253+
:param str path: The path of the file or folder
254+
:param list[cterasdk.core.types.Collaborator] recipients: A list of share recipients
255+
:return: A list of all recipients added
256+
:rtype: list[cterasdk.core.types.Collaborator]
257+
"""
258+
return await io.add_share_recipients(self._core, self.normalize(path), recipients)
259+
260+
async def remove_share_recipients(self, path, accounts):
261+
"""
262+
Remove share recipients
263+
264+
:param str path: The path of the file or folder
265+
:param list[cterasdk.core.types.PortalAccount] accounts: A list of portal user or group accounts
266+
:return: A list of all share recipients removed
267+
:rtype: list[cterasdk.core.types.PortalAccount]
268+
"""
269+
return await io.remove_share_recipients(self._core, self.normalize(path), accounts)
270+
271+
async def unshare(self, path):
272+
"""
273+
Unshare a file or a folder
274+
"""
275+
return await UnShare(io.update_share, self._core, self.normalize(path)).a_execute()

0 commit comments

Comments
 (0)