Use CopyObject to copy objects smaller than 1 GB, and UploadPartCopy to copy objects larger than 1 GB in a versioning-enabled bucket.
Prerequisites
Before you begin, ensure that you have:
The
oss:GetObjectandoss:PutObjectpermissions. For details, see Attach a custom policy to a RAM userOSS SDK for Python V2 installed (
alibabacloud_oss_v2)Your AccessKey ID and AccessKey Secret configured as environment variables for
oss.credentials.EnvironmentVariableCredentialsProvider()
Copy an object
CopyObject copies a source object to a destination bucket in the same region. Use this method for objects smaller than 1 GB.
Versioning behavior
By default, CopyObject copies the current version of the source object. Pass a source_version_id to copy a specific version instead.
| Condition | Result |
|---|---|
| No version ID specified; current version is a delete marker | OSS returns 404 Not Found |
| Version ID specified | OSS copies that specific version |
| Delete marker specified as source | Not supported — delete markers cannot be copied |
| Destination bucket has versioning enabled | OSS assigns a unique version ID to the copied object, returned in the x-oss-version-id response header |
| Destination bucket has versioning disabled or suspended | OSS generates a null version ID and overwrites any previous null-version object |
| Source object is appendable | Cannot be copied to a versioning-enabled or versioning-suspended destination bucket |
Copying an earlier version to the same bucket creates a new current version, effectively restoring that version.
Core API call
result = client.copy_object(oss.CopyObjectRequest(
bucket="<destination-bucket>",
key="<destination-object-key>",
source_bucket="<source-bucket>",
source_key="<source-object-key>",
source_version_id="<source-version-id>", # Omit to copy the current version
))
print(f"version ID: {result.version_id}, source version ID: {result.source_version_id}")Full runnable example
The sample code below uses the cn-hangzhou region and a public endpoint. To access OSS from another Alibaba Cloud service in the same region, use an internal endpoint. For a list of regions and endpoints, see Regions and endpoints.
import argparse
import alibabacloud_oss_v2 as oss
parser = argparse.ArgumentParser(description="copy object sample")
parser.add_argument('--region', required=True, help='Region where the bucket is located.')
parser.add_argument('--bucket', required=True, help='Destination bucket name.')
parser.add_argument('--endpoint', help='Custom endpoint (optional).')
parser.add_argument('--key', required=True, help='Destination object key.')
parser.add_argument('--source_bucket', required=True, help='Source bucket name.')
parser.add_argument('--source_key', required=True, help='Source object key.')
parser.add_argument('--source_version_id', required=True, help='Version ID of the source object.')
def main():
args = parser.parse_args()
credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
cfg = oss.config.load_default()
cfg.credentials_provider = credentials_provider
cfg.region = args.region
if args.endpoint is not None:
cfg.endpoint = args.endpoint
client = oss.Client(cfg)
result = client.copy_object(oss.CopyObjectRequest(
bucket=args.bucket,
key=args.key,
source_bucket=args.source_bucket,
source_key=args.source_key,
source_version_id=args.source_version_id,
))
print(f'status code: {result.status_code},'
f' request id: {result.request_id},'
f' version id: {result.version_id},'
f' hash crc64: {result.hash_crc64},'
f' source version id: {result.source_version_id},'
f' server side encryption: {result.server_side_encryption},'
f' server side data encryption: {result.server_side_data_encryption},'
f' last modified: {result.last_modified},'
f' etag: {result.etag},'
)
if __name__ == "__main__":
main()Multipart copy
For objects larger than 1 GB, use UploadPartCopy. This method requires you to manage the full multipart workflow manually. The process involves four steps:
Get the source object size using GetObjectMeta.
Initiate a multipart upload with InitiateMultipartUpload to get an upload ID.
Split the object into parts and copy each part with UploadPartCopy, specifying a byte range.
Complete the upload with CompleteMultipartUpload after all parts are copied.
Versioning behavior
By default, UploadPartCopy copies a part from the current version of the source object. Pass a source_version_id to copy from a specific version.
| Condition | Result |
|---|---|
| No version ID specified; current version is a delete marker | OSS returns 404 Not Found |
| Version ID specified and corresponds to a delete marker | OSS returns 400 Bad Request |
Full runnable example
import argparse
import alibabacloud_oss_v2 as oss
parser = argparse.ArgumentParser(description="upload part copy synchronously sample")
parser.add_argument('--region', required=True, help='Region where the bucket is located.')
parser.add_argument('--bucket', required=True, help='Destination bucket name.')
parser.add_argument('--endpoint', help='Custom endpoint (optional).')
parser.add_argument('--key', required=True, help='Destination object key.')
parser.add_argument('--source_bucket', required=True, help='Source bucket name.')
parser.add_argument('--source_key', required=True, help='Source object key.')
parser.add_argument('--source_version_id', required=True, help='Version ID of the source object.')
def main():
args = parser.parse_args()
credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
cfg = oss.config.load_default()
cfg.credentials_provider = credentials_provider
cfg.region = args.region
if args.endpoint is not None:
cfg.endpoint = args.endpoint
client = oss.Client(cfg)
# Step 1: Get the source object size
result_meta = client.get_object_meta(oss.GetObjectMetaRequest(
bucket=args.source_bucket,
key=args.source_key,
))
# Step 2: Initiate a multipart upload
result = client.initiate_multipart_upload(oss.InitiateMultipartUploadRequest(
bucket=args.bucket,
key=args.key,
))
# Step 3: Copy each part
part_size = 1024 * 1024 # 1 MB per part
total_size = result_meta.content_length
part_number = 1
upload_parts = []
offset = 0
while offset < total_size:
num_to_upload = min(part_size, total_size - offset)
end = offset + num_to_upload - 1
up_result = client.upload_part_copy(oss.UploadPartCopyRequest(
bucket=args.bucket,
key=args.key,
upload_id=result.upload_id,
part_number=part_number,
source_bucket=args.source_bucket,
source_key=args.source_key,
source_version_id=args.source_version_id,
source_range=f'bytes={offset}-{end}',
))
print(f'status code: {up_result.status_code},'
f' request id: {up_result.request_id},'
f' part number: {part_number},'
f' last modified: {up_result.last_modified},'
f' etag: {up_result.etag},'
f' source version id: {up_result.source_version_id},'
)
upload_parts.append(oss.UploadPart(part_number=part_number, etag=up_result.etag))
offset += num_to_upload
part_number += 1
# Step 4: Complete the multipart upload
parts = sorted(upload_parts, key=lambda p: p.part_number)
result = client.complete_multipart_upload(oss.CompleteMultipartUploadRequest(
bucket=args.bucket,
key=args.key,
upload_id=result.upload_id,
complete_multipart_upload=oss.CompleteMultipartUpload(
parts=parts
)
))
print(f'status code: {result.status_code},'
f' request id: {result.request_id},'
f' bucket: {result.bucket},'
f' key: {result.key},'
f' location: {result.location},'
f' etag: {result.etag},'
f' encoding type: {result.encoding_type},'
f' hash crc64: {result.hash_crc64},'
f' version id: {result.version_id},'
)
if __name__ == "__main__":
main()References
Complete sample for CopyObject: copy_object.py
Complete sample for UploadPartCopy: upload_part_copy.py