async def _get_file_meta(self, path: wb_path.WaterButlerPath, raw: bool=False, revision: str=None) -> typing.Union[dict, BoxFileMetadata]: if revision: url = self.build_url('files', path.identifier, 'versions') else: url = self.build_url('files', path.identifier) async with self.request( 'GET', url, expects=(200, ), throws=exceptions.MetadataError, ) as resp: data = await resp.json() if revision: try: data = next(x for x in data['entries'] if x['id'] == revision) except StopIteration: raise exceptions.NotFoundError(str(path)) if not data: raise exceptions.NotFoundError(str(path)) return data if raw else BoxFileMetadata(data, path)
async def upload( self, # type: ignore stream: streams.BaseStream, path: WaterButlerPath, conflict: str = 'replace', **kwargs) -> Tuple[BoxFileMetadata, bool]: """Upload a file to Box. If the file is less than ``NONCHUNKED_UPLOAD_LIMIT``, upload in a single request. Otherwise, use Box's chunked upload interface to send it across multiple requests. """ if path.identifier and conflict == 'keep': path, _ = await self.handle_name_conflict(path, conflict=conflict, kind='folder') path._parts[-1]._id = None if stream.size > self.NONCHUNKED_UPLOAD_LIMIT: entry = await self._chunked_upload(path, stream) else: entry = await self._contiguous_upload(path, stream) created = path.identifier is None path._parts[-1]._id = entry['id'] return BoxFileMetadata(entry, path), created
def upload(self, stream, path, conflict='replace', **kwargs): if path.identifier and conflict == 'keep': path, _ = self.handle_name_conflict(path, conflict=conflict, kind='folder') path._parts[-1]._id = None data_stream = streams.FormDataStream( attributes=json.dumps({ 'name': path.name, 'parent': { 'id': path.parent.identifier } }) ) data_stream.add_file('file', stream, path.name, disposition='form-data') resp = yield from self.make_request( 'POST', self._build_upload_url(*filter(lambda x: x is not None, ('files', path.identifier, 'content'))), data=data_stream, headers=data_stream.headers, expects=(201,), throws=exceptions.UploadError, ) data = yield from resp.json() return BoxFileMetadata(data['entries'][0], path), path.identifier is None
def test_upload_create(self, provider, folder_object_metadata, folder_list_metadata, file_metadata, file_stream, settings): path = WaterButlerPath('/newfile', _ids=(provider.folder, None)) upload_url = provider._build_upload_url('files', 'content') folder_object_url = provider.build_url('folders', path.parent.identifier) folder_list_url = provider.build_url('folders', path.parent.identifier, 'items') aiohttpretty.register_json_uri('POST', upload_url, status=201, body=file_metadata) metadata, created = yield from provider.upload(file_stream, path) expected = BoxFileMetadata(file_metadata['entries'][0], path).serialized() assert metadata.serialized() == expected assert created is True assert path.identifier_path == metadata.path assert aiohttpretty.has_call(method='POST', uri=upload_url)
def test_metadata(self, provider, folder_object_metadata, folder_list_metadata): path = WaterButlerPath('/', _ids=(provider.folder, )) list_url = provider.build_url('folders', provider.folder, 'items', fields='id,name,size,modified_at,etag') aiohttpretty.register_json_uri('GET', list_url, body=folder_list_metadata) result = yield from provider.metadata(path) expected = [] for x in folder_list_metadata['entries']: if x['type'] == 'file': expected.append(BoxFileMetadata(x, path.child(x['name']))) else: expected.append( BoxFolderMetadata(x, path.child(x['name'], folder=True))) assert result == expected
async def test_metadata(self, provider, root_provider_fixtures): path = WaterButlerPath('/', _ids=(provider.folder, )) list_url = provider.build_url( 'folders', provider.folder, 'items', fields='id,name,size,modified_at,etag,total_count', offset=0, limit=1000) list_metadata = root_provider_fixtures['folder_list_metadata'] aiohttpretty.register_json_uri('GET', list_url, body=list_metadata) result = await provider.metadata(path) expected = [] for x in list_metadata['entries']: if x['type'] == 'file': expected.append(BoxFileMetadata(x, path.child(x['name']))) else: expected.append( BoxFolderMetadata(x, path.child(x['name'], folder=True))) assert result == expected
def test_metadata_nested(self, provider, file_metadata): item = file_metadata['entries'][0] path = WaterButlerPath('/name.txt', _ids=(provider, item['id'])) file_url = provider.build_url('files', path.identifier) aiohttpretty.register_json_uri('GET', file_url, body=item) result = yield from provider.metadata(path) expected = BoxFileMetadata(item, path) assert result == expected assert aiohttpretty.has_call(method='GET', uri=file_url)
def test_upload_update(self, provider, folder_object_metadata, folder_list_metadata, file_metadata, file_stream, settings): item = folder_list_metadata['entries'][0] path = WaterButlerPath('/newfile', _ids=(provider.folder, item['id'])) upload_url = provider._build_upload_url('files', item['id'], 'content') aiohttpretty.register_json_uri('POST', upload_url, status=201, body=file_metadata) metadata, created = yield from provider.upload(file_stream, path) expected = BoxFileMetadata(file_metadata['entries'][0], path).serialized() assert metadata == expected assert created is False assert aiohttpretty.has_call(method='POST', uri=upload_url)
def _get_file_meta(self, path, raw=False): resp = yield from self.make_request( 'GET', self.build_url('files', path.identifier), expects=(200, ), throws=exceptions.MetadataError, ) data = yield from resp.json() if not data: raise exceptions.NotFoundError(str(path)) return data if raw else BoxFileMetadata(data, path)
async def test_intra_move_file(self, provider, root_provider_fixtures): item = root_provider_fixtures['file_metadata']['entries'][0] src_path = WaterButlerPath('/name.txt', _ids=(provider, item['id'])) dest_path = WaterButlerPath('/charmander/name.txt', _ids=(provider, item['id'])) file_url = provider.build_url('files', src_path.identifier) aiohttpretty.register_json_uri('PUT', file_url, body=item) result = await provider.intra_move(provider, src_path, dest_path) expected = (BoxFileMetadata(item, dest_path), True) assert result == expected
async def test_revision_metadata(self, provider, root_provider_fixtures, revision_fixtures): list_metadata = revision_fixtures['revisions_list_metadata'] item = list_metadata['entries'][0] path = WaterButlerPath('/goats', _ids=(provider.folder, item['id'])) url = provider.build_url('files', path.identifier, 'versions') aiohttpretty.register_json_uri('GET', url, body=list_metadata) result = await provider.metadata(path, revision=item['id']) expected = BoxFileMetadata(item, path) assert result == expected
async def test_intra_copy_file_replace(self, provider, root_provider_fixtures): item = root_provider_fixtures['file_metadata']['entries'][0] src_path = WaterButlerPath('/name.txt', _ids=(provider, item['id'])) dest_path = WaterButlerPath('/charmander/name.txt', _ids=(provider, item['id'], item['id'])) file_url = provider.build_url('files', src_path.identifier, 'copy') delete_url = provider.build_url('files', dest_path.identifier) aiohttpretty.register_uri('DELETE', delete_url, status=204) aiohttpretty.register_json_uri('POST', file_url, body=item) result = await provider.intra_copy(provider, src_path, dest_path) expected = (BoxFileMetadata(item, dest_path), False) assert result == expected
async def upload( self, # type: ignore stream: streams.BaseStream, path: WaterButlerPath, conflict: str = 'replace', **kwargs) -> Tuple[BoxFileMetadata, bool]: if path.identifier and conflict == 'keep': path, _ = await self.handle_name_conflict(path, conflict=conflict, kind='folder') path._parts[-1]._id = None stream.add_writer('sha1', streams.HashStreamWriter(hashlib.sha1)) data_stream = streams.FormDataStream( attributes=json.dumps({ 'name': path.name, 'parent': { 'id': path.parent.identifier } })) data_stream.add_file('file', stream, path.name, disposition='form-data') async with self.request( 'POST', self._build_upload_url( *filter(lambda x: x is not None, ('files', path.identifier, 'content'))), data=data_stream, headers=data_stream.headers, expects=(201, ), throws=exceptions.UploadError, ) as resp: data = await resp.json() entry = data['entries'][0] if stream.writers['sha1'].hexdigest != entry['sha1']: raise exceptions.UploadChecksumMismatchError() created = path.identifier is None path._parts[-1]._id = entry['id'] return BoxFileMetadata(entry, path), created
async def test_metadata_nested(self, provider, root_provider_fixtures): item = root_provider_fixtures['file_metadata']['entries'][0] path = WaterButlerPath('/name.txt', _ids=(provider, item['id'])) file_url = provider.build_url('files', path.identifier) aiohttpretty.register_json_uri('GET', file_url, body=item) result = await provider.metadata(path) expected = BoxFileMetadata(item, path) assert result == expected assert aiohttpretty.has_call(method='GET', uri=file_url) assert result.extra == { 'etag': '3', 'hashes': { 'sha1': '134b65991ed521fcfe4724b7d814ab8ded5185dc', }, }
async def test_upload_create(self, provider, root_provider_fixtures, file_stream): path = WaterButlerPath('/newfile', _ids=(provider.folder, None)) upload_url = provider._build_upload_url('files', 'content') upload_metadata = root_provider_fixtures['upload_metadata'] aiohttpretty.register_json_uri('POST', upload_url, status=201, body=upload_metadata) metadata, created = await provider.upload(file_stream, path) expected = BoxFileMetadata(upload_metadata['entries'][0], path).serialized() assert metadata.serialized() == expected assert created is True assert path.identifier_path == metadata.path assert aiohttpretty.has_call(method='POST', uri=upload_url)
async def test_upload_conflict_keep(self, provider, root_provider_fixtures, file_stream): upload_metadata = root_provider_fixtures['upload_metadata'] item = upload_metadata['entries'][0] path = WaterButlerPath('/newfile', _ids=(provider.folder, item['id'])) upload_url = provider._build_upload_url('files', 'content') aiohttpretty.register_json_uri('POST', upload_url, status=201, body=upload_metadata) metadata_url = provider.build_url('files', path.identifier) aiohttpretty.register_json_uri('GET', metadata_url, body=upload_metadata) list_url = provider.build_url( 'folders', item['path_collection']['entries'][1]['id'], 'items', fields='id,name,type', limit=1000) aiohttpretty.register_json_uri( 'GET', list_url, body=root_provider_fixtures['folder_list_metadata']) metadata, created = await provider.upload(file_stream, path, conflict='keep') expected = BoxFileMetadata(item, path).serialized() # since the metadata for the renamed conflict file isn't actually saved, this one is odd to # test. assert metadata.serialized() == expected assert created is True assert path.identifier_path == metadata.path assert aiohttpretty.has_call(method='POST', uri=upload_url)
async def test_upload_update(self, provider, root_provider_fixtures, file_stream): upload_metadata = root_provider_fixtures['upload_metadata'] item_to_overwrite = root_provider_fixtures['folder_list_metadata'][ 'entries'][0] path = WaterButlerPath('/newfile', _ids=(provider.folder, item_to_overwrite['id'])) upload_url = provider._build_upload_url('files', item_to_overwrite['id'], 'content') aiohttpretty.register_json_uri('POST', upload_url, status=201, body=upload_metadata) metadata, created = await provider.upload(file_stream, path) expected = BoxFileMetadata(upload_metadata['entries'][0], path).serialized() assert metadata.serialized() == expected assert created is False assert aiohttpretty.has_call(method='POST', uri=upload_url)
def _get_file_meta(self, path, raw=False, revision=None): if revision: url = self.build_url('files', path.identifier, 'versions') else: url = self.build_url('files', path.identifier) resp = yield from self.make_request( 'GET', url, expects=(200, ), throws=exceptions.MetadataError, ) data = yield from resp.json() if revision: try: data = next(x for x in data['entries'] if x['id'] == revision) except StopIteration: raise exceptions.NotFoundError(str(path)) if not data: raise exceptions.NotFoundError(str(path)) return data if raw else BoxFileMetadata(data, path)
def test_file_metadata(self, root_provider_fixtures): item = root_provider_fixtures['file_metadata']['entries'][0] dest_path = WaterButlerPath('/charmander/name.txt', _ids=('0', item['id'], item['id'])) data = BoxFileMetadata(item, dest_path) assert data.name == 'tigers.jpeg' assert data.path == '/5000948880' assert data.provider == 'box' assert data.size == 629644 assert data.size_as_int == 629644 assert type(data.size_as_int) == int assert data.modified == '2012-12-12T11:04:26-08:00' assert data.created_utc == '2012-12-12T18:55:30+00:00' assert data.content_type is None assert data.etag == '3::5000948880' assert data.extra == { 'etag': '3', 'hashes': { 'sha1': '134b65991ed521fcfe4724b7d814ab8ded5185dc' } } assert data.serialized() == { 'extra': { 'etag': '3', 'hashes': { 'sha1': '134b65991ed521fcfe4724b7d814ab8ded5185dc' } }, 'kind': 'file', 'name': 'tigers.jpeg', 'path': '/5000948880', 'provider': 'box', 'materialized': '/charmander/name.txt', 'etag': 'c14cacfd0701ec2d45e0b8cb89e996f00e2ec861897e8a9656adc12781c889f8', 'contentType': None, 'modified': '2012-12-12T11:04:26-08:00', 'modified_utc': '2012-12-12T19:04:26+00:00', 'created_utc': '2012-12-12T18:55:30+00:00', 'size': 629644, 'sizeInt': 629644, } assert data.kind == 'file' assert data.modified_utc == '2012-12-12T19:04:26+00:00' assert data.json_api_serialized('cn42d') == { 'id': 'box/5000948880', 'type': 'files', 'attributes': { 'extra': { 'etag': '3', 'hashes': { 'sha1': '134b65991ed521fcfe4724b7d814ab8ded5185dc' } }, 'kind': 'file', 'name': 'tigers.jpeg', 'path': '/5000948880', 'provider': 'box', 'materialized': '/charmander/name.txt', 'etag': 'c14cacfd0701ec2d45e0b8cb89e996f00e2ec861897e8a9656adc12781c889f8', 'contentType': None, 'modified': '2012-12-12T11:04:26-08:00', 'modified_utc': '2012-12-12T19:04:26+00:00', 'created_utc': '2012-12-12T18:55:30+00:00', 'size': 629644, 'sizeInt': 629644, 'resource': 'cn42d' }, 'links': { 'move': 'http://localhost:7777/v1/resources/cn42d/providers/box/5000948880', 'upload': ('http://localhost:7777/v1/resources' '/cn42d/providers/box/5000948880?kind=file'), 'delete': 'http://localhost:7777/v1/resources/cn42d/providers/box/5000948880', 'download': 'http://localhost:7777/v1/resources/cn42d/providers/box/5000948880' } }