oci 2.129.1__py3-none-any.whl → 2.129.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oci/access_governance_cp/access_governance_cp_client.py +8 -8
- oci/adm/application_dependency_management_client.py +36 -36
- oci/ai_anomaly_detection/anomaly_detection_client.py +36 -36
- oci/ai_document/ai_service_document_client.py +22 -22
- oci/ai_language/ai_service_language_client.py +44 -44
- oci/ai_speech/ai_service_speech_client.py +10 -10
- oci/ai_vision/ai_service_vision_client.py +25 -25
- oci/analytics/analytics_client.py +23 -23
- oci/announcements_service/announcement_client.py +4 -4
- oci/announcements_service/announcement_subscription_client.py +9 -9
- oci/announcements_service/announcements_preferences_client.py +4 -4
- oci/apigateway/api_gateway_client.py +21 -21
- oci/apigateway/deployment_client.py +6 -6
- oci/apigateway/gateway_client.py +6 -6
- oci/apigateway/subscribers_client.py +6 -6
- oci/apigateway/usage_plans_client.py +6 -6
- oci/apigateway/work_requests_client.py +5 -5
- oci/apm_config/config_client.py +9 -9
- oci/apm_control_plane/apm_domain_client.py +14 -14
- oci/apm_synthetics/apm_synthetic_client.py +28 -28
- oci/apm_traces/attributes_client.py +8 -8
- oci/apm_traces/query_client.py +2 -2
- oci/apm_traces/trace_client.py +4 -4
- oci/appmgmt_control/appmgmt_control_client.py +8 -8
- oci/artifacts/artifacts_client.py +32 -32
- oci/audit/audit_client.py +3 -3
- oci/autoscaling/auto_scaling_client.py +11 -11
- oci/bastion/bastion_client.py +15 -15
- oci/bds/bds_client.py +66 -66
- oci/blockchain/blockchain_platform_client.py +27 -27
- oci/budget/budget_client.py +10 -10
- oci/capacity_management/capacity_management_client.py +22 -22
- oci/certificates/certificates_client.py +5 -5
- oci/certificates_management/certificates_management_client.py +32 -32
- oci/cims/incident_client.py +8 -8
- oci/cims/user_client.py +1 -1
- oci/cloud_bridge/common_client.py +5 -5
- oci/cloud_bridge/discovery_client.py +14 -14
- oci/cloud_bridge/inventory_client.py +16 -16
- oci/cloud_bridge/ocb_agent_svc_client.py +23 -23
- oci/cloud_guard/cloud_guard_client.py +155 -155
- oci/cloud_migrations/migration_client.py +43 -43
- oci/cluster_placement_groups/cluster_placement_groups_cp_client.py +13 -13
- oci/compute_cloud_at_customer/compute_cloud_at_customer_client.py +12 -12
- oci/compute_instance_agent/compute_instance_agent_client.py +6 -6
- oci/compute_instance_agent/plugin_client.py +2 -2
- oci/compute_instance_agent/pluginconfig_client.py +1 -1
- oci/container_engine/container_engine_client.py +44 -44
- oci/container_instances/container_instance_client.py +18 -18
- oci/core/blockstorage_client.py +60 -60
- oci/core/compute_client.py +99 -99
- oci/core/compute_management_client.py +32 -32
- oci/core/virtual_network_client.py +247 -247
- oci/dashboard_service/dashboard_client.py +6 -6
- oci/dashboard_service/dashboard_group_client.py +6 -6
- oci/data_catalog/data_catalog_client.py +149 -149
- oci/data_flow/data_flow_client.py +42 -42
- oci/data_integration/data_integration_client.py +163 -163
- oci/data_labeling_service/data_labeling_management_client.py +17 -17
- oci/data_labeling_service_dataplane/data_labeling_client.py +15 -15
- oci/data_safe/data_safe_client.py +278 -278
- oci/data_science/data_science_client.py +91 -91
- oci/database/database_client.py +466 -352
- oci/database/database_client_composite_operations.py +38 -0
- oci/database/models/create_database_details.py +37 -2
- oci/database/models/key_store.py +7 -3
- oci/database/models/key_store_summary.py +7 -3
- oci/database_management/db_management_client.py +208 -208
- oci/database_management/diagnosability_client.py +4 -4
- oci/database_management/managed_my_sql_databases_client.py +7 -7
- oci/database_management/perfhub_client.py +1 -1
- oci/database_management/sql_tuning_client.py +17 -17
- oci/database_migration/database_migration_client.py +36 -36
- oci/database_tools/database_tools_client.py +23 -23
- oci/demand_signal/occ_demand_signal_client.py +7 -7
- oci/desktops/desktop_service_client.py +21 -21
- oci/devops/devops_client.py +89 -89
- oci/disaster_recovery/disaster_recovery_client.py +29 -29
- oci/dns/dns_client.py +52 -52
- oci/dts/appliance_export_job_client.py +6 -6
- oci/dts/shipping_vendors_client.py +1 -1
- oci/dts/transfer_appliance_client.py +8 -8
- oci/dts/transfer_appliance_entitlement_client.py +3 -3
- oci/dts/transfer_device_client.py +5 -5
- oci/dts/transfer_job_client.py +6 -6
- oci/dts/transfer_package_client.py +7 -7
- oci/em_warehouse/em_data_lake_client.py +13 -13
- oci/em_warehouse/em_warehouse_client.py +13 -13
- oci/email/email_client.py +31 -31
- oci/email_data_plane/email_dp_client.py +1 -1
- oci/events/events_client.py +6 -6
- oci/exceptions.py +46 -7
- oci/file_storage/file_storage_client.py +51 -51
- oci/fleet_software_update/fleet_software_update_client.py +44 -44
- oci/functions/functions_invoke_client.py +1 -1
- oci/functions/functions_management_client.py +16 -16
- oci/fusion_apps/data_masking_activity_client.py +3 -3
- oci/fusion_apps/fusion_applications_client.py +41 -41
- oci/fusion_apps/fusion_environment_client.py +15 -15
- oci/fusion_apps/fusion_environment_family_client.py +8 -8
- oci/fusion_apps/refresh_activity_client.py +4 -4
- oci/fusion_apps/scheduled_activity_client.py +2 -2
- oci/fusion_apps/service_attachment_client.py +2 -2
- oci/generative_ai/generative_ai_client.py +22 -22
- oci/generative_ai_inference/generative_ai_inference_client.py +4 -4
- oci/generic_artifacts_content/generic_artifacts_content_client.py +3 -3
- oci/globally_distributed_database/sharded_database_service_client.py +30 -30
- oci/golden_gate/golden_gate_client.py +68 -68
- oci/governance_rules_control_plane/governance_rule_client.py +15 -15
- oci/governance_rules_control_plane/work_request_client.py +5 -5
- oci/healthchecks/health_checks_client.py +17 -17
- oci/identity/identity_client.py +145 -145
- oci/identity_data_plane/dataplane_client.py +2 -2
- oci/identity_domains/identity_domains_client.py +300 -300
- oci/integration/integration_instance_client.py +15 -15
- oci/jms/java_management_service_client.py +66 -66
- oci/jms_java_downloads/java_download_client.py +25 -25
- oci/key_management/ekm_client.py +5 -5
- oci/key_management/kms_crypto_client.py +6 -6
- oci/key_management/kms_hsm_cluster_client.py +12 -12
- oci/key_management/kms_management_client.py +21 -21
- oci/key_management/kms_vault_client.py +14 -14
- oci/license_manager/license_manager_client.py +18 -18
- oci/limits/limits_client.py +4 -4
- oci/limits/quotas_client.py +7 -7
- oci/load_balancer/load_balancer_client.py +61 -61
- oci/lockbox/lockbox_client.py +24 -24
- oci/log_analytics/log_analytics_client.py +193 -193
- oci/logging/logging_management_client.py +30 -30
- oci/loggingingestion/logging_client.py +1 -1
- oci/loggingsearch/log_search_client.py +1 -1
- oci/management_agent/management_agent_client.py +28 -28
- oci/management_dashboard/dashx_apis_client.py +14 -14
- oci/marketplace/account_client.py +2 -2
- oci/marketplace/marketplace_client.py +30 -30
- oci/marketplace_private_offer/attachment_client.py +5 -5
- oci/marketplace_private_offer/offer_client.py +6 -6
- oci/marketplace_publisher/attachment_client.py +5 -5
- oci/marketplace_publisher/marketplace_publisher_client.py +71 -71
- oci/marketplace_publisher/offer_client.py +6 -6
- oci/media_services/media_services_client.py +60 -60
- oci/media_services/media_stream_client.py +2 -2
- oci/monitoring/monitoring_client.py +18 -18
- oci/mysql/channels_client.py +7 -7
- oci/mysql/db_backups_client.py +7 -7
- oci/mysql/db_system_client.py +17 -17
- oci/mysql/mysqlaas_client.py +7 -7
- oci/mysql/replicas_client.py +5 -5
- oci/mysql/work_requests_client.py +4 -4
- oci/network_firewall/network_firewall_client.py +80 -80
- oci/network_load_balancer/network_load_balancer_client.py +34 -34
- oci/nosql/nosql_client.py +24 -24
- oci/object_storage/__init__.py +2 -1
- oci/object_storage/object_storage_client.py +50 -50
- oci/object_storage/transfer/internal/download/DownloadConfiguration.py +232 -0
- oci/object_storage/transfer/internal/download/DownloadManager.py +902 -0
- oci/object_storage/transfer/internal/download/DownloadThread.py +375 -0
- oci/object_storage/transfer/internal/download/__init__.py +5 -0
- oci/oce/oce_instance_client.py +10 -10
- oci/oci_control_center/occ_metrics_client.py +3 -3
- oci/ocvp/cluster_client.py +5 -5
- oci/ocvp/esxi_host_client.py +8 -8
- oci/ocvp/sddc_client.py +14 -14
- oci/ocvp/work_request_client.py +4 -4
- oci/oda/management_client.py +59 -59
- oci/oda/oda_client.py +17 -17
- oci/oda/odapackage_client.py +7 -7
- oci/onesubscription/billing_schedule_client.py +1 -1
- oci/onesubscription/commitment_client.py +2 -2
- oci/onesubscription/computed_usage_client.py +3 -3
- oci/onesubscription/invoice_summary_client.py +2 -2
- oci/onesubscription/organization_subscription_client.py +1 -1
- oci/onesubscription/ratecard_client.py +1 -1
- oci/onesubscription/subscribed_service_client.py +2 -2
- oci/onesubscription/subscription_client.py +1 -1
- oci/ons/notification_control_plane_client.py +6 -6
- oci/ons/notification_data_plane_client.py +10 -10
- oci/opa/opa_instance_client.py +13 -13
- oci/opensearch/opensearch_cluster_backup_client.py +4 -4
- oci/opensearch/opensearch_cluster_client.py +14 -14
- oci/operator_access_control/access_requests_client.py +10 -10
- oci/operator_access_control/operator_actions_client.py +2 -2
- oci/operator_access_control/operator_control_assignment_client.py +8 -8
- oci/operator_access_control/operator_control_client.py +6 -6
- oci/opsi/operations_insights_client.py +175 -175
- oci/optimizer/optimizer_client.py +26 -26
- oci/os_management/event_client.py +8 -8
- oci/os_management/os_management_client.py +69 -69
- oci/os_management_hub/event_client.py +8 -8
- oci/os_management_hub/lifecycle_environment_client.py +12 -12
- oci/os_management_hub/managed_instance_client.py +31 -31
- oci/os_management_hub/managed_instance_group_client.py +25 -25
- oci/os_management_hub/management_station_client.py +10 -10
- oci/os_management_hub/onboarding_client.py +6 -6
- oci/os_management_hub/reporting_managed_instance_client.py +3 -3
- oci/os_management_hub/scheduled_job_client.py +7 -7
- oci/os_management_hub/software_source_client.py +27 -27
- oci/os_management_hub/work_request_client.py +4 -4
- oci/osp_gateway/address_rule_service_client.py +1 -1
- oci/osp_gateway/address_service_client.py +2 -2
- oci/osp_gateway/invoice_service_client.py +5 -5
- oci/osp_gateway/subscription_service_client.py +5 -5
- oci/osub_billing_schedule/billing_schedule_client.py +1 -1
- oci/osub_organization_subscription/organization_subscription_client.py +1 -1
- oci/osub_subscription/commitment_client.py +2 -2
- oci/osub_subscription/ratecard_client.py +1 -1
- oci/osub_subscription/subscription_client.py +1 -1
- oci/osub_usage/computed_usage_client.py +3 -3
- oci/psql/postgresql_client.py +33 -33
- oci/queue/queue_admin_client.py +11 -11
- oci/queue/queue_client.py +8 -8
- oci/recovery/database_recovery_client.py +25 -25
- oci/redis/redis_cluster_client.py +11 -11
- oci/resource_manager/resource_manager_client.py +52 -52
- oci/resource_scheduler/schedule_client.py +13 -13
- oci/resource_search/resource_search_client.py +3 -3
- oci/rover/rover_bundle_client.py +8 -8
- oci/rover/rover_cluster_client.py +8 -8
- oci/rover/rover_entitlement_client.py +6 -6
- oci/rover/rover_node_client.py +15 -15
- oci/rover/shape_client.py +1 -1
- oci/rover/work_requests_client.py +5 -5
- oci/sch/connector_plugins_client.py +2 -2
- oci/sch/service_connector_client.py +12 -12
- oci/secrets/secrets_client.py +3 -3
- oci/service_catalog/service_catalog_client.py +26 -26
- oci/service_manager_proxy/service_manager_proxy_client.py +2 -2
- oci/service_mesh/service_mesh_client.py +48 -48
- oci/stack_monitoring/stack_monitoring_client.py +64 -64
- oci/streaming/stream_admin_client.py +18 -18
- oci/streaming/stream_client.py +8 -8
- oci/tenant_manager_control_plane/domain_client.py +5 -5
- oci/tenant_manager_control_plane/domain_governance_client.py +5 -5
- oci/tenant_manager_control_plane/governance_client.py +2 -2
- oci/tenant_manager_control_plane/link_client.py +3 -3
- oci/tenant_manager_control_plane/orders_client.py +2 -2
- oci/tenant_manager_control_plane/organization_client.py +10 -10
- oci/tenant_manager_control_plane/recipient_invitation_client.py +5 -5
- oci/tenant_manager_control_plane/sender_invitation_client.py +5 -5
- oci/tenant_manager_control_plane/subscription_client.py +11 -11
- oci/tenant_manager_control_plane/work_request_client.py +4 -4
- oci/threat_intelligence/threatintel_client.py +5 -5
- oci/usage/resources_client.py +2 -2
- oci/usage/rewards_client.py +6 -6
- oci/usage/usagelimits_client.py +1 -1
- oci/usage_api/models/usage_summary.py +62 -0
- oci/usage_api/usageapi_client.py +33 -33
- oci/vault/vaults_client.py +13 -13
- oci/vbs_inst/vbs_instance_client.py +10 -10
- oci/version.py +1 -1
- oci/visual_builder/vb_instance_client.py +13 -13
- oci/vn_monitoring/vn_monitoring_client.py +12 -12
- oci/vulnerability_scanning/vulnerability_scanning_client.py +58 -58
- oci/waa/waa_client.py +13 -13
- oci/waa/work_request_client.py +4 -4
- oci/waas/redirect_client.py +6 -6
- oci/waas/waas_client.py +66 -66
- oci/waf/waf_client.py +24 -24
- oci/work_requests/work_request_client.py +4 -4
- {oci-2.129.1.dist-info → oci-2.129.2.dist-info}/METADATA +1 -1
- {oci-2.129.1.dist-info → oci-2.129.2.dist-info}/RECORD +265 -261
- {oci-2.129.1.dist-info → oci-2.129.2.dist-info}/LICENSE.txt +0 -0
- {oci-2.129.1.dist-info → oci-2.129.2.dist-info}/THIRD_PARTY_LICENSES.txt +0 -0
- {oci-2.129.1.dist-info → oci-2.129.2.dist-info}/WHEEL +0 -0
- {oci-2.129.1.dist-info → oci-2.129.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,902 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
3
|
+
# This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
|
4
|
+
|
5
|
+
import io
|
6
|
+
import six
|
7
|
+
import math
|
8
|
+
import time
|
9
|
+
import warnings
|
10
|
+
from multiprocessing.dummy import Pool
|
11
|
+
from oci.object_storage.transfer.internal.download.DownloadThread import (ParallelDownloader, SequentialDownloader,
|
12
|
+
DownloadState)
|
13
|
+
from oci.exceptions import (ResumableDownloadException, DownloadTerminated, DownloadFailedIncorrectDownloadSize)
|
14
|
+
|
15
|
+
|
16
|
+
class DownloadManager(object):
|
17
|
+
def __init__(self, download_config, object_storage_client, state=DownloadState.DOWNLOADING):
|
18
|
+
"""
|
19
|
+
The DownloadManager constructor provides methods to get an object, store it to a file (given a path) or store it
|
20
|
+
to a stream from the object storage. It splits large downloads into multiple parts to make retires smarter and
|
21
|
+
downloads faster.
|
22
|
+
|
23
|
+
:param DownloadConfiguration download_config: The download configuration
|
24
|
+
|
25
|
+
:param oci.object_storage_config.ObjectStorageClient object_storage_client: The object storage client
|
26
|
+
|
27
|
+
:param DownloadManger.DownloadState state: The state of the download manager. This governs the state of the
|
28
|
+
download. This can be any from the enum
|
29
|
+
~oci.object_storage.transfer.internal.download.DownloadThread.DownloadState, namely DownloadState.DOWNLOADING,
|
30
|
+
DownloadState.PAUSED, DownloadState.TERMINATED.
|
31
|
+
"""
|
32
|
+
self.download_config = download_config
|
33
|
+
self.object_storage_client = object_storage_client
|
34
|
+
self.state = state
|
35
|
+
|
36
|
+
def get_object(self,
|
37
|
+
namespace_name,
|
38
|
+
bucket_name,
|
39
|
+
object_name,
|
40
|
+
start_byte=0,
|
41
|
+
end_byte=None,
|
42
|
+
**kwargs):
|
43
|
+
"""
|
44
|
+
Gets the metadata and body of an object and returns a response. If both start_byte and end_byte are None, then the metadata and
|
45
|
+
content of the full object (of unknown size) is returned. Raises exceptions on failure. If only start_byte is
|
46
|
+
given, then the end_byte is taken as the last byte of the object being downloaded. If only end_byte is
|
47
|
+
given, then the start_byte is the first byte of the object. A ~oci.exceptions.ServiceError is raised if
|
48
|
+
the object is unavailable or the range is wrong. If some unexpected keyword arguments are encountered,
|
49
|
+
then a ValueError exception is raised.
|
50
|
+
|
51
|
+
:param str namespace_name: (required)
|
52
|
+
The Object Storage namespace used for the request.
|
53
|
+
|
54
|
+
:param str bucket_name: (required)
|
55
|
+
The name of the bucket. Avoid entering confidential information.
|
56
|
+
Example: `my-new-bucket1`
|
57
|
+
|
58
|
+
:param str object_name: (required)
|
59
|
+
The name of the object. Avoid entering confidential information.
|
60
|
+
Example: `test/object1.log`
|
61
|
+
|
62
|
+
:param str version_id: (optional)
|
63
|
+
VersionId used to identify a particular version of the object
|
64
|
+
|
65
|
+
:param str if_match: (optional)
|
66
|
+
The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches
|
67
|
+
the ETag of the existing resource, GET and HEAD requests will return the resource and PUT and POST
|
68
|
+
requests will upload the resource.
|
69
|
+
|
70
|
+
:param str if_none_match: (optional)
|
71
|
+
The entity tag (ETag) to avoid matching. Wildcards ('*') are not allowed. If the specified ETag does
|
72
|
+
not match the ETag of the existing resource, the request returns the expected response. If the ETag
|
73
|
+
matches the ETag of the existing resource, the request returns an HTTP 304 status without a response body.
|
74
|
+
|
75
|
+
:param str opc_client_request_id: (optional)
|
76
|
+
The client request ID for tracing.
|
77
|
+
|
78
|
+
:param any start_byte: (optional)
|
79
|
+
The byte in the content of the object from which to start the download.
|
80
|
+
|
81
|
+
:param any end_byte: (optional)
|
82
|
+
The byte in the content of the object from which to stop the download.
|
83
|
+
Note: Both the start_byte and end_byte are included in the download.
|
84
|
+
|
85
|
+
:param str opc_sse_customer_algorithm: (optional)
|
86
|
+
The optional header that specifies \"AES256\" as the encryption algorithm. For more information, see
|
87
|
+
`Using Your Own Keys for Server-Side Encryption`__.
|
88
|
+
|
89
|
+
__ https://docs.cloud.oracle.com/Content/Object/Tasks/usingyourencryptionkeys.htm
|
90
|
+
|
91
|
+
:param str opc_sse_customer_key: (optional)
|
92
|
+
The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or
|
93
|
+
decrypt the data. For more information, see
|
94
|
+
`Using Your Own Keys for Server-Side Encryption`__.
|
95
|
+
|
96
|
+
__ https://docs.cloud.oracle.com/Content/Object/Tasks/usingyourencryptionkeys.htm
|
97
|
+
|
98
|
+
:param str opc_sse_customer_key_sha256: (optional)
|
99
|
+
The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This
|
100
|
+
value is used to check the integrity of the encryption key. For more information, see
|
101
|
+
`Using Your Own Keys for Server-Side Encryption`__.
|
102
|
+
|
103
|
+
__ https://docs.cloud.oracle.com/Content/Object/Tasks/usingyourencryptionkeys.htm
|
104
|
+
|
105
|
+
:param str http_response_content_disposition: (optional)
|
106
|
+
Specify this query parameter to override the value of the Content-Disposition response header in the
|
107
|
+
GetObject response.
|
108
|
+
|
109
|
+
:param str http_response_cache_control: (optional)
|
110
|
+
Specify this query parameter to override the Cache-Control response header in the GetObject
|
111
|
+
response.
|
112
|
+
|
113
|
+
:param str http_response_content_type: (optional)
|
114
|
+
Specify this query parameter to override the Content-Type response header in the GetObject response.
|
115
|
+
|
116
|
+
:param str http_response_content_language: (optional)
|
117
|
+
Specify this query parameter to override the Content-Language response header in the GetObject
|
118
|
+
response.
|
119
|
+
|
120
|
+
:param str http_response_content_encoding: (optional)
|
121
|
+
Specify this query parameter to override the Content-Encoding response header in the GetObject
|
122
|
+
response.
|
123
|
+
|
124
|
+
:param str http_response_expires: (optional)
|
125
|
+
Specify this query parameter to override the Expires response header in the GetObject response.
|
126
|
+
|
127
|
+
:param obj retry_strategy: (optional)
|
128
|
+
A retry strategy to apply to this specific operation/call. This will override any retry strategy
|
129
|
+
set at the client-level.
|
130
|
+
|
131
|
+
This should be one of the strategies available in the :py:mod:`~oci.retry` module. This operation
|
132
|
+
uses :py:data:`~oci.retry.DEFAULT_RETRY_STRATEGY` as default if no retry strategy is provided.
|
133
|
+
The specifics of the default retry strategy are described
|
134
|
+
`here <https://docs.oracle.com/en-us/iaas/tools/python/latest/sdk_behaviors/retries.html>`__.
|
135
|
+
|
136
|
+
To have this operation explicitly not perform any retries, pass an instance of
|
137
|
+
:py:class:`~oci.retry.NoneRetryStrategy`.
|
138
|
+
|
139
|
+
:param bool allow_control_chars: (optional)
|
140
|
+
allow_control_chars is a boolean to indicate whether or not this request should allow control
|
141
|
+
characters in the response object.
|
142
|
+
By default, the response will not allow control characters in strings
|
143
|
+
|
144
|
+
:return: A :class:`~oci.response.Response` object with data of type stream
|
145
|
+
:rtype: :class:`~oci.response.Response`
|
146
|
+
"""
|
147
|
+
|
148
|
+
# Don't accept unknown kwargs
|
149
|
+
expected_kwargs = [
|
150
|
+
"allow_control_chars",
|
151
|
+
"retry_strategy",
|
152
|
+
"version_id",
|
153
|
+
"if_match",
|
154
|
+
"if_none_match",
|
155
|
+
"opc_client_request_id",
|
156
|
+
"opc_sse_customer_algorithm",
|
157
|
+
"opc_sse_customer_key",
|
158
|
+
"opc_sse_customer_key_sha256",
|
159
|
+
"http_response_content_disposition",
|
160
|
+
"http_response_cache_control",
|
161
|
+
"http_response_content_type",
|
162
|
+
"http_response_content_language",
|
163
|
+
"http_response_content_encoding",
|
164
|
+
"http_response_expires"
|
165
|
+
]
|
166
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
167
|
+
if extra_kwargs:
|
168
|
+
raise ValueError(
|
169
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
170
|
+
|
171
|
+
if start_byte is not None:
|
172
|
+
if end_byte is not None:
|
173
|
+
range_header = f"bytes={start_byte}-{end_byte}"
|
174
|
+
else:
|
175
|
+
range_header = f"bytes={start_byte}-"
|
176
|
+
else:
|
177
|
+
if end_byte is not None:
|
178
|
+
range_header = f"bytes=0-{end_byte}"
|
179
|
+
else:
|
180
|
+
range_header = None
|
181
|
+
|
182
|
+
if range_header == "bytes=0-":
|
183
|
+
# This is necessary as this means getting the whole object and this range header will give errors if the
|
184
|
+
# object is of size 0 bytes
|
185
|
+
range_header = None
|
186
|
+
|
187
|
+
object_storage_client = self.object_storage_client
|
188
|
+
|
189
|
+
if 'retry_strategy' not in kwargs:
|
190
|
+
kwargs['retry_strategy'] = self.download_config.make_retry_strategy()
|
191
|
+
|
192
|
+
try:
|
193
|
+
response = object_storage_client.get_object(namespace_name=namespace_name,
|
194
|
+
bucket_name=bucket_name,
|
195
|
+
object_name=object_name,
|
196
|
+
range=range_header,
|
197
|
+
**kwargs)
|
198
|
+
return response
|
199
|
+
except Exception as e:
|
200
|
+
raise e
|
201
|
+
|
202
|
+
def get_object_to_bytes(self,
|
203
|
+
namespace_name,
|
204
|
+
bucket_name,
|
205
|
+
object_name,
|
206
|
+
progress_callback=None,
|
207
|
+
start_byte=0,
|
208
|
+
end_byte=None,
|
209
|
+
**kwargs):
|
210
|
+
|
211
|
+
"""
|
212
|
+
This function is very similar to get_object. However, there is automatic multipart download and smart retries.
|
213
|
+
If some unexpected keyword arguments are encountered, then a ValueError exception is raised.
|
214
|
+
:param str namespace_name: (required)
|
215
|
+
The Object Storage namespace used for the request.
|
216
|
+
|
217
|
+
:param str bucket_name: (required)
|
218
|
+
The name of the bucket. Avoid entering confidential information.
|
219
|
+
Example: `my-new-bucket1`
|
220
|
+
|
221
|
+
:param str object_name: (required)
|
222
|
+
The name of the object. Avoid entering confidential information.
|
223
|
+
Example: `test/object1.log`
|
224
|
+
|
225
|
+
:param function progress_callback: (optional)
|
226
|
+
This function is used to update the progress bar of the download operation.
|
227
|
+
The arguments that it takes are (total_bytes_downloaded_so_far, total_bytes_to_download)
|
228
|
+
|
229
|
+
:param any start_byte: (optional)
|
230
|
+
The byte in the content of the object from which to start the download.
|
231
|
+
|
232
|
+
:param any end_byte: (optional)
|
233
|
+
The byte in the content of the object from which to stop the download.
|
234
|
+
Note: Both the start_byte and end_byte are included in the download.
|
235
|
+
|
236
|
+
:return: A :class:`~oci.response.Response` object with data of type io.BytesIO()
|
237
|
+
:rtype: :class:`~oci.response.Response`
|
238
|
+
"""
|
239
|
+
|
240
|
+
# Don't accept unknown kwargs
|
241
|
+
expected_kwargs = [
|
242
|
+
"allow_control_chars",
|
243
|
+
"retry_strategy",
|
244
|
+
"version_id",
|
245
|
+
"if_match",
|
246
|
+
"if_none_match",
|
247
|
+
"opc_client_request_id",
|
248
|
+
"opc_sse_customer_algorithm",
|
249
|
+
"opc_sse_customer_key",
|
250
|
+
"opc_sse_customer_key_sha256",
|
251
|
+
"http_response_content_disposition",
|
252
|
+
"http_response_cache_control",
|
253
|
+
"http_response_content_type",
|
254
|
+
"http_response_content_language",
|
255
|
+
"http_response_content_encoding",
|
256
|
+
"http_response_expires"
|
257
|
+
]
|
258
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
259
|
+
if extra_kwargs:
|
260
|
+
raise ValueError(
|
261
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
262
|
+
|
263
|
+
stream = io.BytesIO()
|
264
|
+
response = self.get_object_to_stream(namespace_name, bucket_name, object_name, stream, progress_callback,
|
265
|
+
start_byte, end_byte, **kwargs)
|
266
|
+
response.data = stream.getvalue()
|
267
|
+
return response
|
268
|
+
|
269
|
+
def get_object_to_text(self,
|
270
|
+
namespace_name,
|
271
|
+
bucket_name,
|
272
|
+
object_name,
|
273
|
+
progress_callback=None,
|
274
|
+
start_byte=0,
|
275
|
+
end_byte=None,
|
276
|
+
encoding='utf-8',
|
277
|
+
**kwargs):
|
278
|
+
|
279
|
+
"""This function is similar to the get_object_to_bytes function, but it will also decode the content and return
|
280
|
+
the response object. If some unexpected keyword arguments are encountered, then a ValueError exception is
|
281
|
+
raised.
|
282
|
+
|
283
|
+
:param str namespace_name: (required)
|
284
|
+
The Object Storage namespace used for the request.
|
285
|
+
|
286
|
+
:param str bucket_name: (required)
|
287
|
+
The name of the bucket. Avoid entering confidential information.
|
288
|
+
Example: `my-new-bucket1`
|
289
|
+
|
290
|
+
:param str object_name: (required)
|
291
|
+
The name of the object. Avoid entering confidential information.
|
292
|
+
Example: `test/object1.log`
|
293
|
+
|
294
|
+
:param function progress_callback: (optional)
|
295
|
+
This function is used to update the progress bar of the download operation.
|
296
|
+
The arguments that it takes are (total_bytes_downloaded_so_far, total_bytes_to_download)
|
297
|
+
|
298
|
+
:param any start_byte: (optional)
|
299
|
+
The byte in the content of the object from which to start the download.
|
300
|
+
|
301
|
+
:param any end_byte: (optional)
|
302
|
+
The byte in the content of the object from which to stop the download.
|
303
|
+
Note: Both the start_byte and end_byte are included in the download.
|
304
|
+
|
305
|
+
:param str encoding: (optional) The default value of encoding is 'utf-8'.
|
306
|
+
|
307
|
+
:return: A :class:`~oci.response.Response` object with decoded data.
|
308
|
+
:rtype: :class:`~oci.response.Response`
|
309
|
+
"""
|
310
|
+
# Don't accept unknown kwargs
|
311
|
+
expected_kwargs = [
|
312
|
+
"allow_control_chars",
|
313
|
+
"retry_strategy",
|
314
|
+
"version_id",
|
315
|
+
"if_match",
|
316
|
+
"if_none_match",
|
317
|
+
"opc_client_request_id",
|
318
|
+
"opc_sse_customer_algorithm",
|
319
|
+
"opc_sse_customer_key",
|
320
|
+
"opc_sse_customer_key_sha256",
|
321
|
+
"http_response_content_disposition",
|
322
|
+
"http_response_cache_control",
|
323
|
+
"http_response_content_type",
|
324
|
+
"http_response_content_language",
|
325
|
+
"http_response_content_encoding",
|
326
|
+
"http_response_expires"
|
327
|
+
]
|
328
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
329
|
+
if extra_kwargs:
|
330
|
+
raise ValueError(
|
331
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
332
|
+
|
333
|
+
response = self.get_object_to_bytes(namespace_name, bucket_name, object_name, progress_callback, start_byte,
|
334
|
+
end_byte, **kwargs)
|
335
|
+
response.data = response.data.decode(encoding)
|
336
|
+
|
337
|
+
return response
|
338
|
+
|
339
|
+
def get_object_to_path(self,
|
340
|
+
namespace_name,
|
341
|
+
bucket_name,
|
342
|
+
object_name,
|
343
|
+
destination_path=None,
|
344
|
+
progress_callback=None,
|
345
|
+
start_byte=0,
|
346
|
+
end_byte=None,
|
347
|
+
**kwargs
|
348
|
+
):
|
349
|
+
"""
|
350
|
+
Puts the content of the object into the file specified by the path.
|
351
|
+
If all went well, it returns a response object where the data is None (as it is already written to
|
352
|
+
disk). Connection is closed. Else, there are three types of exceptions that can be raised.
|
353
|
+
ResumableDownloadException is raised when some parts from a multipart download failed. These parts are
|
354
|
+
as an attribute of the exception. The user can use these only retry these parts as the rest of the parts
|
355
|
+
would already be written. Hence, it is advised to use this method in a try and except block.
|
356
|
+
The file addressed by destination_path will be created if it does not exist. An empty file will be
|
357
|
+
created even if the download failed or was cancelled. If the destination path is not specified then a
|
358
|
+
file name "download_"+object_name is created in the directory the program was executed in.
|
359
|
+
A ~oci.exceptions.ServiceError is raised if the object is unavailable or the range is wrong.
|
360
|
+
The integrity of the download is verified by checking if the downloaded bytes (i.e. the number of bytes
|
361
|
+
written into the file) is the same as the object size. If this fails, then an
|
362
|
+
~oci.exceptions.DownloadFailedIncorrectDownloadSize exception is raised. If some unexpected keyword
|
363
|
+
arguments are encountered, then a ValueError exception is raised.
|
364
|
+
|
365
|
+
:param str namespace_name: (required)
|
366
|
+
The Object Storage namespace used for the request.
|
367
|
+
|
368
|
+
:param str bucket_name: (required)
|
369
|
+
The name of the bucket. Avoid entering confidential information.
|
370
|
+
Example: `my-new-bucket1`
|
371
|
+
|
372
|
+
:param str object_name: (required)
|
373
|
+
The name of the object. Avoid entering confidential information.
|
374
|
+
Example: `test/object1.log`
|
375
|
+
|
376
|
+
:param str destination_path: (required)
|
377
|
+
The path of the file where the object's content must be stored.
|
378
|
+
|
379
|
+
:param function progress_callback: (optional)
|
380
|
+
This function is used to update the progress bar of the download operation.
|
381
|
+
The arguments that it takes are (total_bytes_downloaded_so_far, total_bytes_to_download)
|
382
|
+
|
383
|
+
:param any start_byte: (optional)
|
384
|
+
The byte in the content of the object from which to start the download.
|
385
|
+
|
386
|
+
:param any end_byte: (optional)
|
387
|
+
The byte in the content of the object from which to stop the download.
|
388
|
+
Note: Both the start_byte and end_byte are included in the download.
|
389
|
+
|
390
|
+
:param str version_id: (optional)
|
391
|
+
VersionId used to identify a particular version of the object
|
392
|
+
|
393
|
+
:param str if_match: (optional)
|
394
|
+
The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches
|
395
|
+
the ETag of the existing resource, GET and HEAD requests will return the resource and PUT and POST
|
396
|
+
requests will upload the resource.
|
397
|
+
|
398
|
+
:param str if_none_match: (optional)
|
399
|
+
The entity tag (ETag) to avoid matching. Wildcards ('*') are not allowed. If the specified ETag does
|
400
|
+
not match the ETag of the existing resource, the request returns the expected response. If the ETag
|
401
|
+
matches the ETag of the existing resource, the request returns an HTTP 304 status without a response
|
402
|
+
body.
|
403
|
+
|
404
|
+
:param str opc_client_request_id: (optional)
|
405
|
+
The client request ID for tracing.
|
406
|
+
|
407
|
+
|
408
|
+
:param str opc_sse_customer_algorithm: (optional)
|
409
|
+
The optional header that specifies \"AES256\" as the encryption algorithm. For more information, see
|
410
|
+
`Using Your Own Keys for Server-Side Encryption`__.
|
411
|
+
|
412
|
+
__ https://docs.cloud.oracle.com/Content/Object/Tasks/usingyourencryptionkeys.htm
|
413
|
+
|
414
|
+
:param str opc_sse_customer_key: (optional)
|
415
|
+
The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or
|
416
|
+
decrypt the data. For more information, see
|
417
|
+
`Using Your Own Keys for Server-Side Encryption`__.
|
418
|
+
|
419
|
+
__ https://docs.cloud.oracle.com/Content/Object/Tasks/usingyourencryptionkeys.htm
|
420
|
+
|
421
|
+
:param str opc_sse_customer_key_sha256: (optional)
|
422
|
+
The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This
|
423
|
+
value is used to check the integrity of the encryption key. For more information, see
|
424
|
+
`Using Your Own Keys for Server-Side Encryption`__.
|
425
|
+
|
426
|
+
__ https://docs.cloud.oracle.com/Content/Object/Tasks/usingyourencryptionkeys.htm
|
427
|
+
|
428
|
+
:param str http_response_content_disposition: (optional)
|
429
|
+
Specify this query parameter to override the value of the Content-Disposition response header in the
|
430
|
+
GetObject response.
|
431
|
+
|
432
|
+
:param str http_response_cache_control: (optional)
|
433
|
+
Specify this query parameter to override the Cache-Control response header in the GetObject
|
434
|
+
response.
|
435
|
+
|
436
|
+
:param str http_response_content_type: (optional)
|
437
|
+
Specify this query parameter to override the Content-Type response header in the GetObject response.
|
438
|
+
|
439
|
+
:param str http_response_content_language: (optional)
|
440
|
+
Specify this query parameter to override the Content-Language response header in the GetObject
|
441
|
+
response.
|
442
|
+
|
443
|
+
:param str http_response_content_encoding: (optional)
|
444
|
+
Specify this query parameter to override the Content-Encoding response header in the GetObject
|
445
|
+
response.
|
446
|
+
|
447
|
+
:param str http_response_expires: (optional)
|
448
|
+
Specify this query parameter to override the Expires response header in the GetObject response.
|
449
|
+
|
450
|
+
:param obj retry_strategy: (optional)
|
451
|
+
A retry strategy to apply to this specific operation/call. This will override any retry strategy
|
452
|
+
set at the client-level.
|
453
|
+
|
454
|
+
This should be one of the strategies available in the :py:mod:`~oci.retry` module. This operation
|
455
|
+
uses :py:data:`~oci.retry.DEFAULT_RETRY_STRATEGY` as default if no retry strategy is provided.
|
456
|
+
The specifics of the default retry strategy are described
|
457
|
+
`here <https://docs.oracle.com/en-us/iaas/tools/python/latest/sdk_behaviors/retries.html>`__.
|
458
|
+
|
459
|
+
To have this operation explicitly not perform any retries, pass an instance of
|
460
|
+
:py:class:`~oci.retry.NoneRetryStrategy`.
|
461
|
+
|
462
|
+
:param bool allow_control_chars: (optional)
|
463
|
+
allow_control_chars is a boolean to indicate whether or not this request should allow control
|
464
|
+
characters in the response object.
|
465
|
+
By default, the response will not allow control characters in strings
|
466
|
+
|
467
|
+
:return: A :tuple:(int bytes downloaded, `~oci.response.Response` object with data of type None)
|
468
|
+
:rtype: :tuple:(int, `~oci.response.Response`)
|
469
|
+
"""
|
470
|
+
# Don't accept unknown kwargs
|
471
|
+
expected_kwargs = [
|
472
|
+
"allow_control_chars",
|
473
|
+
"retry_strategy",
|
474
|
+
"version_id",
|
475
|
+
"if_match",
|
476
|
+
"if_none_match",
|
477
|
+
"opc_client_request_id",
|
478
|
+
"opc_sse_customer_algorithm",
|
479
|
+
"opc_sse_customer_key",
|
480
|
+
"opc_sse_customer_key_sha256",
|
481
|
+
"http_response_content_disposition",
|
482
|
+
"http_response_cache_control",
|
483
|
+
"http_response_content_type",
|
484
|
+
"http_response_content_language",
|
485
|
+
"http_response_content_encoding",
|
486
|
+
"http_response_expires"
|
487
|
+
]
|
488
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
489
|
+
if extra_kwargs:
|
490
|
+
raise ValueError(
|
491
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
492
|
+
|
493
|
+
if destination_path is None:
|
494
|
+
destination_path = "download_" + object_name
|
495
|
+
|
496
|
+
with io.open(destination_path, 'wb') as out_stream:
|
497
|
+
bytes_written, response = self.get_object_to_stream(namespace_name, bucket_name, object_name, out_stream,
|
498
|
+
progress_callback, start_byte, end_byte, **kwargs)
|
499
|
+
return bytes_written, response
|
500
|
+
|
501
|
+
def get_object_to_stream(self,
|
502
|
+
namespace_name,
|
503
|
+
bucket_name,
|
504
|
+
object_name,
|
505
|
+
stream,
|
506
|
+
progress_callback=None,
|
507
|
+
start_byte=0,
|
508
|
+
end_byte=None,
|
509
|
+
**kwargs
|
510
|
+
):
|
511
|
+
"""
|
512
|
+
This function gets the object and dumps the object data into the provided stream. Other behaviour is similar to
|
513
|
+
get_object_to_path. If some unexpected keyword arguments are encountered, then a ValueError exception is raised.
|
514
|
+
|
515
|
+
:return: A :tuple:(int bytes downloaded, `~oci.response.Response` object with data of type None)
|
516
|
+
:rtype: :tuple:(int, `~oci.response.Response`)
|
517
|
+
"""
|
518
|
+
# Don't accept unknown kwargs
|
519
|
+
expected_kwargs = [
|
520
|
+
"allow_control_chars",
|
521
|
+
"retry_strategy",
|
522
|
+
"version_id",
|
523
|
+
"if_match",
|
524
|
+
"if_none_match",
|
525
|
+
"opc_client_request_id",
|
526
|
+
"opc_sse_customer_algorithm",
|
527
|
+
"opc_sse_customer_key",
|
528
|
+
"opc_sse_customer_key_sha256",
|
529
|
+
"http_response_content_disposition",
|
530
|
+
"http_response_cache_control",
|
531
|
+
"http_response_content_type",
|
532
|
+
"http_response_content_language",
|
533
|
+
"http_response_content_encoding",
|
534
|
+
"http_response_expires"
|
535
|
+
]
|
536
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
537
|
+
if extra_kwargs:
|
538
|
+
raise ValueError(
|
539
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
540
|
+
|
541
|
+
if 'retry_strategy' not in kwargs:
|
542
|
+
kwargs['retry_strategy'] = self.download_config.make_retry_strategy()
|
543
|
+
|
544
|
+
download_config = self.download_config
|
545
|
+
do_multithread = download_config.get_allow_multipart()
|
546
|
+
|
547
|
+
if download_config.get_num_download_threads() > 1:
|
548
|
+
if not stream.seekable(): # Check if the stream is seekable or not
|
549
|
+
warnings.warn("The stream provided is not seekable. Performing single threaded download")
|
550
|
+
do_multithread = False
|
551
|
+
|
552
|
+
if (start_byte is not None) and (end_byte is not None):
|
553
|
+
if download_config.get_part_size_in_bytes() > (end_byte - start_byte + 1):
|
554
|
+
do_multithread = False
|
555
|
+
|
556
|
+
response = self.get_object(namespace_name, bucket_name, object_name, start_byte, end_byte, **kwargs)
|
557
|
+
|
558
|
+
object_size_in_bytes = int(response.headers['Content-Length'])
|
559
|
+
|
560
|
+
if object_size_in_bytes == 0:
|
561
|
+
return 0, response
|
562
|
+
|
563
|
+
if not do_multithread:
|
564
|
+
try:
|
565
|
+
bytes_downloaded = 0
|
566
|
+
|
567
|
+
for chunk in response.data.iter_content(chunk_size=download_config.get_part_size_in_bytes()):
|
568
|
+
while self.state == DownloadState.PAUSED:
|
569
|
+
time.sleep(self.download_config.get_pause_wait_in_seconds())
|
570
|
+
if self.state == DownloadState.TERMINATED:
|
571
|
+
stream.seek(0)
|
572
|
+
stream.truncate()
|
573
|
+
raise DownloadTerminated("Download canceled, Thread Stopped")
|
574
|
+
|
575
|
+
start = stream.tell()
|
576
|
+
stream.write(chunk)
|
577
|
+
end = stream.tell()
|
578
|
+
bytes_downloaded += (end - start)
|
579
|
+
if progress_callback:
|
580
|
+
progress_callback(bytes_downloaded,
|
581
|
+
object_size_in_bytes)
|
582
|
+
response.data = None
|
583
|
+
|
584
|
+
# Perform a simple integrity check by seeing if the total bytes downloaded are what we need.
|
585
|
+
if bytes_downloaded != object_size_in_bytes:
|
586
|
+
raise DownloadFailedIncorrectDownloadSize(bytes_downloaded,
|
587
|
+
object_size_in_bytes)
|
588
|
+
return bytes_downloaded, response
|
589
|
+
|
590
|
+
except Exception as e:
|
591
|
+
raise e
|
592
|
+
|
593
|
+
else:
|
594
|
+
# Now we need to identify the right start and end offset values for the first part. We need it to find the
|
595
|
+
# right number of byte to download. We also need to set the end_byte if None appropriately as the
|
596
|
+
# object_size_in_bytes will not have the full object's size in bytes. It will change if the user specifies
|
597
|
+
# a start offset.
|
598
|
+
|
599
|
+
if start_byte is None:
|
600
|
+
if end_byte is None:
|
601
|
+
first_part_start_offset = 0
|
602
|
+
# The first part can be bigger than the total object if the object is small. Here the last byte of
|
603
|
+
# the first part can either be the last byte of the object or the appropriate value for a part.
|
604
|
+
first_part_end_offset = min(object_size_in_bytes - 1, download_config.part_size_in_bytes - 1)
|
605
|
+
# Set the end_byte to the last byte of the object. The end_byte is different from the
|
606
|
+
# first_part_end_offset
|
607
|
+
end_byte = object_size_in_bytes - 1
|
608
|
+
else:
|
609
|
+
first_part_start_offset = 0
|
610
|
+
# Here the last byte of the first part can be the object's last byte, the last requested byte or the
|
611
|
+
# appropriate value for a part.
|
612
|
+
first_part_end_offset = min(object_size_in_bytes - 1, end_byte,
|
613
|
+
download_config.part_size_in_bytes - 1)
|
614
|
+
else:
|
615
|
+
if end_byte is None:
|
616
|
+
first_part_start_offset = start_byte
|
617
|
+
# Here the last byte of the first part can be the object's last byte (content length + start_byte),
|
618
|
+
# or the appropriate value of a part.
|
619
|
+
first_part_end_offset = min(start_byte + object_size_in_bytes - 1,
|
620
|
+
start_byte + download_config.part_size_in_bytes - 1)
|
621
|
+
# Since the object size returned is less than the actual by the start byte requested, we add it.
|
622
|
+
end_byte = object_size_in_bytes - 1 + start_byte
|
623
|
+
|
624
|
+
else:
|
625
|
+
first_part_start_offset = start_byte
|
626
|
+
# Here the last byte of the first part can be the object's last byte (content length + start_byte),
|
627
|
+
# the requested last byte, or the appropriate value of a part.
|
628
|
+
first_part_end_offset = min(start_byte + object_size_in_bytes - 1, end_byte,
|
629
|
+
start_byte + download_config.part_size_in_bytes - 1)
|
630
|
+
|
631
|
+
bytes_to_download = min(object_size_in_bytes, first_part_end_offset - first_part_start_offset + 1)
|
632
|
+
|
633
|
+
kwargs["if_match"] = response.headers['ETag']
|
634
|
+
|
635
|
+
stream_start = stream.tell()
|
636
|
+
stream.write(next(response.data.iter_content(chunk_size=bytes_to_download)))
|
637
|
+
stream_end = stream.tell()
|
638
|
+
|
639
|
+
bytes_downloaded = stream_end - stream_start
|
640
|
+
|
641
|
+
if progress_callback:
|
642
|
+
progress_callback(bytes_downloaded, object_size_in_bytes)
|
643
|
+
response.data = None
|
644
|
+
|
645
|
+
if first_part_end_offset >= end_byte:
|
646
|
+
|
647
|
+
# Perform a simple integrity check by seeing if the total bytes downloaded are what we need.
|
648
|
+
if bytes_downloaded != object_size_in_bytes:
|
649
|
+
raise DownloadFailedIncorrectDownloadSize(bytes_downloaded,
|
650
|
+
object_size_in_bytes)
|
651
|
+
|
652
|
+
return bytes_downloaded, response
|
653
|
+
else:
|
654
|
+
total_bytes_downloaded = self.__get_in_parts_to_stream(namespace_name, bucket_name, object_name, stream,
|
655
|
+
bytes_downloaded, object_size_in_bytes,
|
656
|
+
progress_callback, first_part_end_offset + 1,
|
657
|
+
end_byte, **kwargs)
|
658
|
+
|
659
|
+
# Perform a simple integrity check by seeing if the total bytes downloaded are what we need.
|
660
|
+
if total_bytes_downloaded != object_size_in_bytes:
|
661
|
+
raise DownloadFailedIncorrectDownloadSize(total_bytes_downloaded,
|
662
|
+
object_size_in_bytes)
|
663
|
+
|
664
|
+
return total_bytes_downloaded, response
|
665
|
+
|
666
|
+
def __get_in_parts_to_stream(self,
|
667
|
+
namespace_name,
|
668
|
+
bucket_name,
|
669
|
+
object_name,
|
670
|
+
stream,
|
671
|
+
bytes_downloaded,
|
672
|
+
object_size,
|
673
|
+
progress_callback=None,
|
674
|
+
start_byte=0,
|
675
|
+
end_byte=None,
|
676
|
+
**kwargs
|
677
|
+
):
|
678
|
+
|
679
|
+
"""
|
680
|
+
A private function called by get_object_to_stream if multipart download is to be done.
|
681
|
+
Returns a response object with data of type None. A ~oci.exceptions.ServiceError is raised if the object is
|
682
|
+
unavailable or the range is wrong. A ~oci.exceptions.ResumableDownloadException occurs when some parts fail to
|
683
|
+
download. These parts are present in the exception raised. If some
|
684
|
+
unexpected keyword arguments are encountered, then a ValueError exception is raised.
|
685
|
+
|
686
|
+
:return: An integer. It returns the number of bytes downloaded into the stream.
|
687
|
+
:rtype: int
|
688
|
+
"""
|
689
|
+
# Don't accept unknown kwargs
|
690
|
+
expected_kwargs = [
|
691
|
+
"allow_control_chars",
|
692
|
+
"retry_strategy",
|
693
|
+
"version_id",
|
694
|
+
"if_match",
|
695
|
+
"if_none_match",
|
696
|
+
"opc_client_request_id",
|
697
|
+
"opc_sse_customer_algorithm",
|
698
|
+
"opc_sse_customer_key",
|
699
|
+
"opc_sse_customer_key_sha256",
|
700
|
+
"http_response_content_disposition",
|
701
|
+
"http_response_cache_control",
|
702
|
+
"http_response_content_type",
|
703
|
+
"http_response_content_language",
|
704
|
+
"http_response_content_encoding",
|
705
|
+
"http_response_expires"
|
706
|
+
]
|
707
|
+
|
708
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
709
|
+
if extra_kwargs:
|
710
|
+
raise ValueError(
|
711
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
712
|
+
|
713
|
+
download_config = self.download_config
|
714
|
+
num_parts = math.ceil((end_byte - start_byte + 1) / download_config.part_size_in_bytes)
|
715
|
+
num_actual_threads = min(num_parts, download_config.get_num_download_threads())
|
716
|
+
|
717
|
+
if num_actual_threads > 1:
|
718
|
+
parallel_downloader = ParallelDownloader(self, download_config, self.object_storage_client, namespace_name,
|
719
|
+
bucket_name, object_name, stream, bytes_downloaded, object_size,
|
720
|
+
progress_callback,
|
721
|
+
start_byte, end_byte, **kwargs)
|
722
|
+
|
723
|
+
with Pool(processes=num_actual_threads) as pool:
|
724
|
+
pool.map(parallel_downloader.get_part_with_start_byte, parallel_downloader.get_start_bytes())
|
725
|
+
|
726
|
+
total_bytes_downloaded = parallel_downloader.get_response()
|
727
|
+
|
728
|
+
if total_bytes_downloaded == -1:
|
729
|
+
raise ResumableDownloadException(namespace_name,
|
730
|
+
bucket_name,
|
731
|
+
object_name,
|
732
|
+
parallel_downloader.failed_parts # Failed parts has the failed and the
|
733
|
+
# exception raised.
|
734
|
+
)
|
735
|
+
else:
|
736
|
+
return total_bytes_downloaded
|
737
|
+
|
738
|
+
else:
|
739
|
+
sequential_downloader = SequentialDownloader(self, download_config, self.object_storage_client,
|
740
|
+
namespace_name, bucket_name, object_name, stream,
|
741
|
+
bytes_downloaded, object_size,
|
742
|
+
progress_callback, start_byte, end_byte, **kwargs)
|
743
|
+
|
744
|
+
for part in sequential_downloader.get_start_bytes():
|
745
|
+
sequential_downloader.get_part_with_start_byte(part)
|
746
|
+
|
747
|
+
total_bytes_downloaded = sequential_downloader.get_response()
|
748
|
+
|
749
|
+
if total_bytes_downloaded == -1:
|
750
|
+
raise ResumableDownloadException(namespace_name,
|
751
|
+
bucket_name,
|
752
|
+
object_name,
|
753
|
+
sequential_downloader.failed_parts
|
754
|
+
# Failed parts has the failed and the
|
755
|
+
# exception raised.
|
756
|
+
)
|
757
|
+
else:
|
758
|
+
return total_bytes_downloaded
|
759
|
+
|
760
|
+
def resume_parts_to_path_multithread(self, namespace_name, bucket_name, object_name, parts, destination_path,
|
761
|
+
**kwargs):
|
762
|
+
"""
|
763
|
+
This method used to download a set of parts into the same offset into the file at `destination_path`. For
|
764
|
+
example part (100,600) will be written into the file from the 100th byte. This is usually used to download the
|
765
|
+
failed parts in a multipart download. If some parts again fail to download and is captured, then a
|
766
|
+
~oci.exceptions.ResumableDownloadException exception is raised. The integrity of the download is verified by
|
767
|
+
checking if the downloaded bytes (i.e. the number of bytes written into the file) is the same as the object
|
768
|
+
size. If this fails, then an ~oci.exceptions.DownloadFailedIncorrectDownloadSize exception is raised. If some
|
769
|
+
unexpected keyword arguments are encountered, then a ValueError exception is raised. It returns the number of
|
770
|
+
bytes downloaded into the stream.
|
771
|
+
|
772
|
+
|
773
|
+
:param: str namespace_name: (required)
|
774
|
+
The namespace name.
|
775
|
+
:param: str bucket_name: (required)
|
776
|
+
The bucket name.
|
777
|
+
:param: str object_name: (required)
|
778
|
+
The object name.
|
779
|
+
:param: iterable parts: (required)
|
780
|
+
A list of the parts to download. It should of the form ((start_byte,end_byte),
|
781
|
+
(start_byte,end_byte),...).
|
782
|
+
:param: str destination_path: (required)
|
783
|
+
The destination path.
|
784
|
+
|
785
|
+
:return: An integer. It returns the number of bytes downloaded into the stream.
|
786
|
+
:rtype: int
|
787
|
+
"""
|
788
|
+
expected_kwargs = [
|
789
|
+
"allow_control_chars",
|
790
|
+
"retry_strategy",
|
791
|
+
"version_id",
|
792
|
+
"if_match",
|
793
|
+
"if_none_match",
|
794
|
+
"opc_client_request_id",
|
795
|
+
"opc_sse_customer_algorithm",
|
796
|
+
"opc_sse_customer_key",
|
797
|
+
"opc_sse_customer_key_sha256",
|
798
|
+
"http_response_content_disposition",
|
799
|
+
"http_response_cache_control",
|
800
|
+
"http_response_content_type",
|
801
|
+
"http_response_content_language",
|
802
|
+
"http_response_content_encoding",
|
803
|
+
"http_response_expires"
|
804
|
+
]
|
805
|
+
|
806
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
807
|
+
if extra_kwargs:
|
808
|
+
raise ValueError(
|
809
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
810
|
+
|
811
|
+
with io.open(destination_path, "r+b") as out_stream:
|
812
|
+
return self.resume_parts_to_stream_multithread(namespace_name, bucket_name, object_name, parts, out_stream,
|
813
|
+
**kwargs)
|
814
|
+
|
815
|
+
def resume_parts_to_stream_multithread(self, namespace_name, bucket_name, object_name, parts, stream, **kwargs):
|
816
|
+
"""
|
817
|
+
This method used to download a set of parts into the same offset into the stream. For example
|
818
|
+
part (100,600) will be written into the file from the 100th byte. This is usually used to download the failed
|
819
|
+
parts in a multipart download. If some parts again fail to download and is captured, then a
|
820
|
+
~oci.exceptions.ResumableDownloadException exception is raised. The integrity of the download is verified by
|
821
|
+
checking if the downloaded bytes (i.e. the number of bytes written into the file) is the same as the object
|
822
|
+
size. If this fails, then an ~oci.exceptions.DownloadFailedIncorrectDownloadSize exception is raised. If some
|
823
|
+
unexpected keyword arguments are encountered, then a ValueError exception is raised. It returns the number of
|
824
|
+
bytes downloaded into the stream.
|
825
|
+
|
826
|
+
|
827
|
+
:param: str namespace_name: (required)
|
828
|
+
The namespace name.
|
829
|
+
:param: str bucket_name: (required)
|
830
|
+
The bucket name.
|
831
|
+
:param: str object_name: (required)
|
832
|
+
The object name.
|
833
|
+
:param: iterable parts: (required)
|
834
|
+
A list of the parts to download. It should of the form [(start_byte,end_byte),
|
835
|
+
(start_byte,end_byte),...].
|
836
|
+
:param: bytestream stream: (required)
|
837
|
+
The destination stream.
|
838
|
+
|
839
|
+
:return: An integer. It returns the number of bytes downloaded into the stream.
|
840
|
+
:rtype: int
|
841
|
+
"""
|
842
|
+
expected_kwargs = [
|
843
|
+
"allow_control_chars",
|
844
|
+
"retry_strategy",
|
845
|
+
"version_id",
|
846
|
+
"if_match",
|
847
|
+
"if_none_match",
|
848
|
+
"opc_client_request_id",
|
849
|
+
"opc_sse_customer_algorithm",
|
850
|
+
"opc_sse_customer_key",
|
851
|
+
"opc_sse_customer_key_sha256",
|
852
|
+
"http_response_content_disposition",
|
853
|
+
"http_response_cache_control",
|
854
|
+
"http_response_content_type",
|
855
|
+
"http_response_content_language",
|
856
|
+
"http_response_content_encoding",
|
857
|
+
"http_response_expires"
|
858
|
+
]
|
859
|
+
|
860
|
+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
|
861
|
+
if extra_kwargs:
|
862
|
+
raise ValueError(
|
863
|
+
f"get_object got unknown kwargs: {extra_kwargs!r}")
|
864
|
+
|
865
|
+
total_size = sum([part[1] - part[0] + 1 for part in parts])
|
866
|
+
num_threads = min(self.download_config.get_num_download_threads(), len(parts))
|
867
|
+
|
868
|
+
if num_threads == 0:
|
869
|
+
return 0
|
870
|
+
|
871
|
+
parallel_downloader = ParallelDownloader(
|
872
|
+
self, self.download_config, self.object_storage_client,
|
873
|
+
namespace_name, bucket_name, object_name, stream, 0, total_size, **kwargs
|
874
|
+
)
|
875
|
+
|
876
|
+
with Pool(processes=num_threads) as pool:
|
877
|
+
pool.map(parallel_downloader.get_part_with_start_byte, self.__get_start_byte_from_parts(parts))
|
878
|
+
|
879
|
+
total_bytes_downloaded = parallel_downloader.get_response()
|
880
|
+
|
881
|
+
if total_bytes_downloaded == -1:
|
882
|
+
raise ResumableDownloadException(namespace_name,
|
883
|
+
bucket_name,
|
884
|
+
object_name,
|
885
|
+
parallel_downloader.failed_parts
|
886
|
+
)
|
887
|
+
|
888
|
+
if total_bytes_downloaded != total_size:
|
889
|
+
raise DownloadFailedIncorrectDownloadSize(total_bytes_downloaded,
|
890
|
+
total_size)
|
891
|
+
else:
|
892
|
+
return total_bytes_downloaded
|
893
|
+
|
894
|
+
def __get_start_byte_from_parts(self, parts):
|
895
|
+
"""
|
896
|
+
Private helper function to yield the start byte from an iterable of parts
|
897
|
+
|
898
|
+
:param: iterable parts - A list of the parts to download of the form [(start_byte,end_byte),
|
899
|
+
(start_byte,end_byte),...].
|
900
|
+
"""
|
901
|
+
for part in parts:
|
902
|
+
yield part[0]
|