tosnativeclient 1.0.2__tar.gz → 1.0.5__tar.gz

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.

Potentially problematic release.


This version of tosnativeclient might be problematic. Click here for more details.

@@ -1521,7 +1521,7 @@ dependencies = [
1521
1521
 
1522
1522
  [[package]]
1523
1523
  name = "tosnativeclient"
1524
- version = "1.0.2"
1524
+ version = "1.0.5"
1525
1525
  dependencies = [
1526
1526
  "arc-swap",
1527
1527
  "async-channel",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tosnativeclient"
3
- version = "1.0.2"
3
+ version = "1.0.5"
4
4
  edition = "2021"
5
5
  publish = false
6
6
  authors = ["xiangshijian"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tosnativeclient
3
- Version: 1.0.2
3
+ Version: 1.0.5
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -31,6 +31,8 @@ class ListStream(object):
31
31
  prefix: str
32
32
  delimiter: str
33
33
  max_keys: int
34
+ continuation_token: str
35
+ start_after: str
34
36
 
35
37
  def __iter__(self) -> ListStream: ...
36
38
 
@@ -38,6 +40,10 @@ class ListStream(object):
38
40
 
39
41
  def close(self) -> None: ...
40
42
 
43
+ def current_prefix(self) -> Optional[str]: ...
44
+
45
+ def current_continuation_token(self) -> Optional[str]: ...
46
+
41
47
 
42
48
  class ReadStream(object):
43
49
  bucket: str
@@ -45,7 +51,7 @@ class ReadStream(object):
45
51
  size: int
46
52
  etag: str
47
53
 
48
- def read(self, offset: int, length: int) -> bytes:
54
+ def read(self, offset: int, length: int) -> Optional[bytes]:
49
55
  ...
50
56
 
51
57
  def close(self) -> None:
@@ -72,13 +78,18 @@ class TosClient(object):
72
78
  part_size: int
73
79
  max_retry_count: int
74
80
  max_prefetch_tasks: int
81
+ directives: str
82
+ directory: str
83
+ file_name_prefix: str
84
+ shared_prefetch_tasks: int
75
85
 
76
86
  def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', part_size: int = 8388608,
77
87
  max_retry_count: int = 3, max_prefetch_tasks: int = 3, directives: str = '', directory: str = '',
78
88
  file_name_prefix: str = '', shared_prefetch_tasks: int = 20):
79
89
  ...
80
90
 
81
- def list_objects(self, bucket: str, prefix: str = '', max_keys: int = 1000, delimiter: str = '') -> ListStream:
91
+ def list_objects(self, bucket: str, prefix: str = '', max_keys: int = 1000, delimiter: str = '',
92
+ continuation_token: str = '', start_after: str = '') -> ListStream:
82
93
  ...
83
94
 
84
95
  def head_object(self, bucket: str, key: str) -> TosObject:
@@ -147,10 +158,10 @@ class GetObjectOutput(object):
147
158
  content_range: str
148
159
  hash_crc64ecma: int
149
160
 
150
- def read_all(self) -> bytes:
161
+ def read_all(self) -> Optional[bytes]:
151
162
  ...
152
163
 
153
- def read(self) -> bytes:
164
+ def read(self) -> Optional[bytes]:
154
165
  ...
155
166
 
156
167
 
@@ -3,7 +3,8 @@ use crate::tos_error::{map_error_from_string, map_tos_error};
3
3
  use crate::tos_model::ListObjectsResult;
4
4
  use arc_swap::ArcSwap;
5
5
  use async_channel::Receiver;
6
- use pyo3::{pyclass, pymethods, PyRef, PyRefMut, PyResult, Python};
6
+ use pyo3::types::PyTuple;
7
+ use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyRefMut, PyResult, Python};
7
8
  use std::sync::atomic::{AtomicI8, Ordering};
8
9
  use std::sync::{Arc, RwLock};
9
10
  use tokio::runtime::Runtime;
@@ -12,7 +13,7 @@ use ve_tos_rust_sdk::error::TosError;
12
13
  use ve_tos_rust_sdk::object::{ListObjectsType2Input, ListObjectsType2Output};
13
14
 
14
15
  const DEFAULT_TASK_COUNT: usize = 5;
15
- #[pyclass(name = "ListStream")]
16
+ #[pyclass(name = "ListStream", module = "tosnativeclient")]
16
17
  pub struct ListStream {
17
18
  client: Arc<InnerTosClient>,
18
19
  runtime: Arc<Runtime>,
@@ -26,6 +27,10 @@ pub struct ListStream {
26
27
  delimiter: String,
27
28
  #[pyo3(get)]
28
29
  max_keys: isize,
30
+ #[pyo3(get)]
31
+ continuation_token: String,
32
+ #[pyo3(get)]
33
+ start_after: String,
29
34
  }
30
35
 
31
36
  #[pymethods]
@@ -63,6 +68,22 @@ impl ListStream {
63
68
  }
64
69
  }
65
70
  }
71
+
72
+ pub fn current_prefix(&self) -> PyResult<Option<String>> {
73
+ let pg = self.paginator.read().unwrap();
74
+ match pg.as_ref() {
75
+ None => Ok(None),
76
+ Some(pg) => Ok(Some(pg.current_prefix())),
77
+ }
78
+ }
79
+
80
+ pub fn current_continuation_token(&self) -> PyResult<Option<String>> {
81
+ let pg = self.paginator.read().unwrap();
82
+ match pg.as_ref() {
83
+ None => Ok(None),
84
+ Some(pg) => Ok(Some(pg.current_continuation_token())),
85
+ }
86
+ }
66
87
  }
67
88
 
68
89
  impl ListStream {
@@ -73,6 +94,8 @@ impl ListStream {
73
94
  prefix: String,
74
95
  delimiter: String,
75
96
  max_keys: isize,
97
+ continuation_token: String,
98
+ start_after: String,
76
99
  ) -> Self {
77
100
  Self {
78
101
  client,
@@ -83,6 +106,8 @@ impl ListStream {
83
106
  prefix,
84
107
  delimiter,
85
108
  max_keys,
109
+ continuation_token,
110
+ start_after,
86
111
  }
87
112
  }
88
113
 
@@ -93,7 +118,12 @@ impl ListStream {
93
118
  input.set_prefix(self.prefix.as_str());
94
119
  input.set_max_keys(self.max_keys);
95
120
  input.set_delimiter(self.delimiter.as_str());
96
-
121
+ if self.continuation_token != "" {
122
+ input.set_continuation_token(self.continuation_token.as_str());
123
+ }
124
+ if self.start_after != "" {
125
+ input.set_start_after(self.start_after.as_str());
126
+ }
97
127
  py.allow_threads(|| {
98
128
  self.runtime.spawn(async move {
99
129
  let mut need_break = false;
@@ -157,6 +187,7 @@ impl ListStream {
157
187
  is_end: ArcSwap::new(Arc::new(false)),
158
188
  last_err: ArcSwap::new(Arc::new(None)),
159
189
  current_prefix: ArcSwap::new(Arc::new(self.prefix.clone())),
190
+ current_continuation_token: ArcSwap::new(Arc::new(self.continuation_token.clone())),
160
191
  receiver,
161
192
  })
162
193
  }
@@ -195,6 +226,7 @@ pub(crate) struct Paginator {
195
226
  is_end: ArcSwap<bool>,
196
227
  last_err: ArcSwap<Option<TosError>>,
197
228
  current_prefix: ArcSwap<String>,
229
+ current_continuation_token: ArcSwap<String>,
198
230
  receiver: Receiver<(bool, Result<ListObjectsType2Output, TosError>)>,
199
231
  }
200
232
 
@@ -206,8 +238,11 @@ impl Paginator {
206
238
  Ok(!*self.is_end.load().as_ref())
207
239
  }
208
240
 
209
- fn current_prefix(&self) -> Arc<String> {
210
- self.current_prefix.load().clone()
241
+ fn current_prefix(&self) -> String {
242
+ self.current_prefix.load().to_string()
243
+ }
244
+ fn current_continuation_token(&self) -> String {
245
+ self.current_continuation_token.load().to_string()
211
246
  }
212
247
  async fn next_page(&self) -> Result<ListObjectsType2Output, TosError> {
213
248
  if let Some(e) = self.last_err.load().as_ref() {
@@ -236,6 +271,8 @@ impl Paginator {
236
271
  Ok(output) => {
237
272
  self.current_prefix
238
273
  .store(Arc::new(output.prefix().to_string()));
274
+ self.current_continuation_token
275
+ .store(Arc::new(output.continuation_token().to_string()));
239
276
  if is_end {
240
277
  self.is_end.store(Arc::new(true));
241
278
  }
@@ -4,8 +4,8 @@ use crate::tos_model::TosObject;
4
4
  use async_channel::{Receiver, Sender};
5
5
  use bytes::Bytes;
6
6
  use futures_util::StreamExt;
7
- use pyo3::types::PyBytes;
8
- use pyo3::{pyclass, pymethods, Bound, PyRef, PyResult};
7
+ use pyo3::types::{PyBytes, PyTuple};
8
+ use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyResult};
9
9
  use std::collections::LinkedList;
10
10
  use std::sync::atomic::{AtomicI8, AtomicIsize, Ordering};
11
11
  use std::sync::Arc;
@@ -24,7 +24,7 @@ const DEFAULT_PART_SIZE: isize = 8 * 1024 * 1024;
24
24
  const DEFAULT_FETCH_RETRY_COUNT: isize = 3;
25
25
  const DEFAULT_SHARED_PREFETCH_TASK_LIMIT: isize = 100;
26
26
 
27
- #[pyclass(name = "ReadStream")]
27
+ #[pyclass(name = "ReadStream", module = "tosnativeclient")]
28
28
  pub struct ReadStream {
29
29
  object_fetcher: Arc<ObjectFetcher>,
30
30
  runtime: Arc<Runtime>,
@@ -117,6 +117,7 @@ impl ReadStream {
117
117
  Self {
118
118
  object_fetcher: Arc::new(ObjectFetcher {
119
119
  client,
120
+ runtime: runtime.clone(),
120
121
  closed: Arc::new(AtomicI8::new(0)),
121
122
  pc,
122
123
  fc: Mutex::new(fc),
@@ -149,6 +150,7 @@ impl ReadStream {
149
150
 
150
151
  struct ObjectFetcher {
151
152
  client: Arc<InnerTosClient>,
153
+ runtime: Arc<Runtime>,
152
154
  closed: Arc<AtomicI8>,
153
155
  pc: PrefetchConfig,
154
156
  fc: Mutex<FetchContext>,
@@ -295,7 +297,7 @@ impl ObjectFetcher {
295
297
  if fc.has_tasks() {
296
298
  fc.current = fc.pop_task()
297
299
  } else {
298
- fc.current = self.start_fetch_task(fc);
300
+ fc.current = self.start_fetch_task(fc, self.runtime.clone());
299
301
  }
300
302
  }
301
303
  Some(current) => {
@@ -304,17 +306,17 @@ impl ObjectFetcher {
304
306
  if fc.has_tasks() {
305
307
  fc.current = fc.pop_task()
306
308
  } else {
307
- fc.current = self.start_fetch_task(fc);
309
+ fc.current = self.start_fetch_task(fc, self.runtime.clone());
308
310
  }
309
311
  } else if fc.exceed_sequential_read_threshold() {
310
312
  if fc.can_add_task(self.pc.max_prefetch_tasks) {
311
- if let Some(next) = self.start_fetch_task(fc) {
313
+ if let Some(next) = self.start_fetch_task(fc, self.runtime.clone()) {
312
314
  fc.push_task(next, false);
313
315
  }
314
316
  } else if fc.can_steal_shared_task(self.pc.shared_prefetch_task_limit)
315
317
  && fc.pcontext.try_steal_shared_prefetch_task()
316
318
  {
317
- match self.start_fetch_task(fc) {
319
+ match self.start_fetch_task(fc, self.runtime.clone()) {
318
320
  Some(mut next) => {
319
321
  next.is_shared = true;
320
322
  fc.steal_shared_task();
@@ -330,14 +332,18 @@ impl ObjectFetcher {
330
332
  }
331
333
  }
332
334
 
333
- fn start_fetch_task(&self, fc: &mut MutexGuard<'_, FetchContext>) -> Option<FetchTask> {
335
+ fn start_fetch_task(
336
+ &self,
337
+ fc: &mut MutexGuard<'_, FetchContext>,
338
+ runtime: Arc<Runtime>,
339
+ ) -> Option<FetchTask> {
334
340
  if fc.next_request_offset >= self.om.size {
335
341
  return None;
336
342
  }
337
343
 
338
344
  let task = self.new_fetch_task(fc);
339
345
  self.revise_next_request_offset_and_size(fc, task.size);
340
- task.async_fetch(self.client.clone());
346
+ task.async_fetch(self.client.clone(), runtime);
341
347
  Some(task)
342
348
  }
343
349
 
@@ -660,9 +666,9 @@ impl FetchTask {
660
666
  self.start_offset + self.fetched_size.load(Ordering::Acquire)
661
667
  }
662
668
 
663
- fn async_fetch(&self, client: Arc<InnerTosClient>) {
669
+ fn async_fetch(&self, client: Arc<InnerTosClient>, runtime: Arc<Runtime>) {
664
670
  let fetch_task_context = FetchTaskContext::new(self, client);
665
- Handle::current().spawn(async move {
671
+ runtime.spawn(async move {
666
672
  fetch_task_context.fetch_from_server().await;
667
673
  fetch_task_context.chunk_queue.close();
668
674
  });
@@ -5,7 +5,9 @@ use crate::tos_model::TosObject;
5
5
  use crate::write_stream::WriteStream;
6
6
  use async_trait::async_trait;
7
7
  use futures_util::future::BoxFuture;
8
- use pyo3::{pyclass, pymethods, PyRef, PyResult};
8
+ use pyo3::prelude::PyDictMethods;
9
+ use pyo3::types::{PyDict, PyTuple};
10
+ use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyAny, PyObject, PyRef, PyRefMut, PyResult};
9
11
  use std::future::Future;
10
12
  use std::sync::atomic::{AtomicIsize, Ordering};
11
13
  use std::sync::Arc;
@@ -53,7 +55,7 @@ impl AsyncRuntime for TokioRuntime {
53
55
  pub(crate) type InnerTosClient =
54
56
  TosClientImpl<CommonCredentialsProvider<CommonCredentials>, CommonCredentials, TokioRuntime>;
55
57
 
56
- #[pyclass(name = "TosClient")]
58
+ #[pyclass(name = "TosClient", module = "tosnativeclient")]
57
59
  pub struct TosClient {
58
60
  rclient: Arc<InnerTosClient>,
59
61
  wclient: Arc<InnerTosClient>,
@@ -75,6 +77,14 @@ pub struct TosClient {
75
77
  max_retry_count: isize,
76
78
  #[pyo3(get)]
77
79
  max_prefetch_tasks: isize,
80
+ #[pyo3(get)]
81
+ directives: String,
82
+ #[pyo3(get)]
83
+ directory: String,
84
+ #[pyo3(get)]
85
+ file_name_prefix: String,
86
+ #[pyo3(get)]
87
+ shared_prefetch_tasks: isize,
78
88
  }
79
89
 
80
90
  #[pymethods]
@@ -97,7 +107,11 @@ impl TosClient {
97
107
  ) -> PyResult<Self> {
98
108
  let mut _guard = None;
99
109
  if directives != "" {
100
- _guard = Some(init_tracing_log(directives, directory, file_name_prefix));
110
+ _guard = Some(init_tracing_log(
111
+ directives.clone(),
112
+ directory.clone(),
113
+ file_name_prefix.clone(),
114
+ ));
101
115
  }
102
116
 
103
117
  let logical_cores = num_cpus::get();
@@ -142,16 +156,22 @@ impl TosClient {
142
156
  part_size,
143
157
  max_retry_count,
144
158
  max_prefetch_tasks,
159
+ directives,
160
+ directory,
161
+ file_name_prefix,
162
+ shared_prefetch_tasks,
145
163
  })
146
164
  }
147
165
 
148
- #[pyo3(signature = (bucket, prefix=String::from(""), max_keys=1000, delimiter=String::from("")))]
166
+ #[pyo3(signature = (bucket, prefix=String::from(""), max_keys=1000, delimiter=String::from(""), continuation_token=String::from(""), start_after=String::from("")))]
149
167
  pub fn list_objects(
150
168
  &self,
151
169
  bucket: String,
152
170
  prefix: String,
153
171
  max_keys: isize,
154
172
  delimiter: String,
173
+ continuation_token: String,
174
+ start_after: String,
155
175
  ) -> ListStream {
156
176
  ListStream::new(
157
177
  self.rclient.clone(),
@@ -160,6 +180,8 @@ impl TosClient {
160
180
  prefix,
161
181
  delimiter,
162
182
  max_keys,
183
+ continuation_token,
184
+ start_after,
163
185
  )
164
186
  }
165
187
  pub fn head_object(slf: PyRef<'_, Self>, bucket: String, key: String) -> PyResult<TosObject> {
@@ -210,6 +232,24 @@ impl TosClient {
210
232
  })
211
233
  })
212
234
  }
235
+
236
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
237
+ let py = slf.py();
238
+ let state = [
239
+ slf.region.clone().into_pyobject(py)?.into_any(),
240
+ slf.endpoint.clone().into_pyobject(py)?.into_any(),
241
+ slf.ak.clone().into_pyobject(py)?.into_any(),
242
+ slf.sk.clone().into_pyobject(py)?.into_any(),
243
+ slf.part_size.into_pyobject(py)?.into_any(),
244
+ slf.max_retry_count.into_pyobject(py)?.into_any(),
245
+ slf.max_prefetch_tasks.into_pyobject(py)?.into_any(),
246
+ "".into_pyobject(py)?.into_any(),
247
+ "".into_pyobject(py)?.into_any(),
248
+ "".into_pyobject(py)?.into_any(),
249
+ slf.shared_prefetch_tasks.into_pyobject(py)?.into_any(),
250
+ ];
251
+ PyTuple::new(py, state)
252
+ }
213
253
  }
214
254
 
215
255
  pub(crate) struct SharedPrefetchContext {
@@ -1,9 +1,10 @@
1
1
  use pyo3::exceptions::PyException;
2
- use pyo3::{create_exception, pyclass, pymethods, PyErr};
2
+ use pyo3::types::PyTuple;
3
+ use pyo3::{create_exception, pyclass, pymethods, Bound, IntoPyObject, PyErr, PyRef, PyResult};
3
4
  use std::error::Error;
4
5
 
5
- #[pyclass]
6
6
  #[derive(Clone)]
7
+ #[pyclass(name = "TosError", module = "tosnativeclient")]
7
8
  pub struct TosError {
8
9
  #[pyo3(get)]
9
10
  message: String,
@@ -43,6 +44,17 @@ impl TosError {
43
44
  request_id,
44
45
  }
45
46
  }
47
+
48
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
49
+ let py = slf.py();
50
+ let state = [
51
+ slf.message.clone().into_pyobject(py)?.into_any(),
52
+ slf.status_code.clone().into_pyobject(py)?.into_any(),
53
+ slf.ec.clone().into_pyobject(py)?.into_any(),
54
+ slf.request_id.clone().into_pyobject(py)?.into_any(),
55
+ ];
56
+ PyTuple::new(py, state)
57
+ }
46
58
  }
47
59
 
48
60
  create_exception!(tosnativeclient, TosException, PyException);
@@ -1,7 +1,7 @@
1
1
  use pyo3::pyclass;
2
2
  use ve_tos_rust_sdk::object::{HeadObjectOutput, ListObjectsType2Output};
3
3
 
4
- #[pyclass(name = "ListObjectsResult")]
4
+ #[pyclass(name = "ListObjectsResult", module = "tosnativeclient")]
5
5
  pub struct ListObjectsResult {
6
6
  #[pyo3(get)]
7
7
  contents: Vec<TosObject>,
@@ -33,7 +33,7 @@ impl ListObjectsResult {
33
33
  }
34
34
 
35
35
  #[derive(Clone)]
36
- #[pyclass(name = "TosObject")]
36
+ #[pyclass(name = "TosObject", module = "tosnativeclient")]
37
37
  pub struct TosObject {
38
38
  #[pyo3(get)]
39
39
  pub(crate) bucket: String,
@@ -2,8 +2,10 @@ use crate::tos_client::{InnerTosClient, TokioRuntime};
2
2
  use crate::tos_error::{map_error, map_tos_error};
3
3
  use bytes::Buf;
4
4
  use futures_util::StreamExt;
5
- use pyo3::{pyclass, pymethods, PyRef, PyRefMut, PyResult};
5
+ use pyo3::types::PyTuple;
6
+ use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyRefMut, PyResult};
6
7
  use std::collections::HashMap;
8
+ use std::sync::atomic::{AtomicI8, Ordering};
7
9
  use std::sync::Arc;
8
10
  use tokio::runtime;
9
11
  use tokio::runtime::Runtime;
@@ -11,7 +13,7 @@ use tokio::sync::Mutex;
11
13
  use ve_tos_rust_sdk::asynchronous::object::{ObjectAPI, ObjectContent};
12
14
  use ve_tos_rust_sdk::asynchronous::tos;
13
15
 
14
- #[pyclass(name = "TosRawClient")]
16
+ #[pyclass(name = "TosRawClient", module = "tosnativeclient")]
15
17
  pub struct TosRawClient {
16
18
  client: Arc<InnerTosClient>,
17
19
  runtime: Arc<Runtime>,
@@ -158,7 +160,7 @@ impl TosRawClient {
158
160
  content_range: output.content_range().to_string(),
159
161
  hash_crc64ecma: output.hash_crc64ecma(),
160
162
  output: Arc::new(Mutex::new(output)),
161
- runtime: runtime.clone(),
163
+ runtime,
162
164
  }),
163
165
  }
164
166
  })
@@ -218,9 +220,24 @@ impl TosRawClient {
218
220
  })
219
221
  })
220
222
  }
223
+
224
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
225
+ let py = slf.py();
226
+ let state = [
227
+ slf.region.clone().into_pyobject(py)?.into_any(),
228
+ slf.endpoint.clone().into_pyobject(py)?.into_any(),
229
+ slf.ak.clone().into_pyobject(py)?.into_any(),
230
+ slf.sk.clone().into_pyobject(py)?.into_any(),
231
+ slf.connection_timeout.into_pyobject(py)?.into_any(),
232
+ slf.request_timeout.into_pyobject(py)?.into_any(),
233
+ slf.max_connections.into_pyobject(py)?.into_any(),
234
+ slf.max_retry_count.into_pyobject(py)?.into_any(),
235
+ ];
236
+ PyTuple::new(py, state)
237
+ }
221
238
  }
222
239
 
223
- #[pyclass(name = "HeadObjectInput")]
240
+ #[pyclass(name = "HeadObjectInput", module = "tosnativeclient")]
224
241
  pub struct HeadObjectInput {
225
242
  #[pyo3(get, set)]
226
243
  pub(crate) bucket: String,
@@ -241,9 +258,18 @@ impl HeadObjectInput {
241
258
  version_id: version_id.to_string(),
242
259
  })
243
260
  }
261
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
262
+ let py = slf.py();
263
+ let state = [
264
+ slf.bucket.clone().into_pyobject(py)?.into_any(),
265
+ slf.key.clone().into_pyobject(py)?.into_any(),
266
+ slf.version_id.clone().into_pyobject(py)?.into_any(),
267
+ ];
268
+ PyTuple::new(py, state)
269
+ }
244
270
  }
245
271
 
246
- #[pyclass(name = "HeadObjectOutput")]
272
+ #[pyclass(name = "HeadObjectOutput", module = "tosnativeclient")]
247
273
  pub struct HeadObjectOutput {
248
274
  #[pyo3(get)]
249
275
  pub(crate) request_id: String,
@@ -261,7 +287,7 @@ pub struct HeadObjectOutput {
261
287
  pub(crate) hash_crc64ecma: u64,
262
288
  }
263
289
 
264
- #[pyclass(name = "DeleteObjectInput")]
290
+ #[pyclass(name = "DeleteObjectInput", module = "tosnativeclient")]
265
291
  pub struct DeleteObjectInput {
266
292
  #[pyo3(get, set)]
267
293
  pub(crate) bucket: String,
@@ -282,9 +308,18 @@ impl DeleteObjectInput {
282
308
  version_id: version_id.to_string(),
283
309
  })
284
310
  }
311
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
312
+ let py = slf.py();
313
+ let state = [
314
+ slf.bucket.clone().into_pyobject(py)?.into_any(),
315
+ slf.key.clone().into_pyobject(py)?.into_any(),
316
+ slf.version_id.clone().into_pyobject(py)?.into_any(),
317
+ ];
318
+ PyTuple::new(py, state)
319
+ }
285
320
  }
286
321
 
287
- #[pyclass(name = "DeleteObjectOutput")]
322
+ #[pyclass(name = "DeleteObjectOutput", module = "tosnativeclient")]
288
323
  pub struct DeleteObjectOutput {
289
324
  #[pyo3(get)]
290
325
  pub(crate) request_id: String,
@@ -297,7 +332,7 @@ pub struct DeleteObjectOutput {
297
332
  #[pyo3(get)]
298
333
  pub(crate) version_id: String,
299
334
  }
300
- #[pyclass(name = "GetObjectInput")]
335
+ #[pyclass(name = "GetObjectInput", module = "tosnativeclient")]
301
336
  pub struct GetObjectInput {
302
337
  #[pyo3(get, set)]
303
338
  pub(crate) bucket: String,
@@ -321,9 +356,19 @@ impl GetObjectInput {
321
356
  range: range.to_string(),
322
357
  })
323
358
  }
359
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
360
+ let py = slf.py();
361
+ let state = [
362
+ slf.bucket.clone().into_pyobject(py)?.into_any(),
363
+ slf.key.clone().into_pyobject(py)?.into_any(),
364
+ slf.version_id.clone().into_pyobject(py)?.into_any(),
365
+ slf.range.clone().into_pyobject(py)?.into_any(),
366
+ ];
367
+ PyTuple::new(py, state)
368
+ }
324
369
  }
325
370
 
326
- #[pyclass(name = "GetObjectOutput")]
371
+ #[pyclass(name = "GetObjectOutput", module = "tosnativeclient")]
327
372
  pub struct GetObjectOutput {
328
373
  #[pyo3(get)]
329
374
  pub(crate) request_id: String,
@@ -350,30 +395,34 @@ impl GetObjectOutput {
350
395
  pub fn read_all(slf: PyRefMut<'_, Self>) -> PyResult<Option<Vec<u8>>> {
351
396
  let runtime = slf.runtime.clone();
352
397
  let output = slf.output.clone();
353
- runtime.block_on(async move {
354
- match output.lock().await.read_all().await {
355
- Err(ex) => Err(map_tos_error(ex)),
356
- Ok(buf) => Ok(Some(buf)),
357
- }
398
+ slf.py().allow_threads(|| {
399
+ runtime.block_on(async move {
400
+ match output.lock().await.read_all().await {
401
+ Err(ex) => Err(map_tos_error(ex)),
402
+ Ok(buf) => Ok(Some(buf)),
403
+ }
404
+ })
358
405
  })
359
406
  }
360
407
 
361
408
  pub fn read(slf: PyRefMut<'_, Self>) -> PyResult<Option<Vec<u8>>> {
362
409
  let runtime = slf.runtime.clone();
363
410
  let output = slf.output.clone();
364
- runtime.block_on(async move {
365
- match output.lock().await.next().await {
366
- None => Ok(None),
367
- Some(result) => match result {
368
- Err(ex) => Err(map_error(ex)),
369
- Ok(buf) => Ok(Some(buf.chunk().to_vec())),
370
- },
371
- }
411
+ slf.py().allow_threads(|| {
412
+ runtime.block_on(async move {
413
+ match output.lock().await.next().await {
414
+ None => Ok(None),
415
+ Some(result) => match result {
416
+ Err(ex) => Err(map_error(ex)),
417
+ Ok(buf) => Ok(Some(buf.chunk().to_vec())),
418
+ },
419
+ }
420
+ })
372
421
  })
373
422
  }
374
423
  }
375
424
 
376
- #[pyclass(name = "PutObjectFromBufferInput")]
425
+ #[pyclass(name = "PutObjectFromBufferInput", module = "tosnativeclient")]
377
426
  pub struct PutObjectFromBufferInput {
378
427
  #[pyo3(get, set)]
379
428
  pub(crate) bucket: String,
@@ -394,9 +443,18 @@ impl PutObjectFromBufferInput {
394
443
  content: content.to_vec(),
395
444
  })
396
445
  }
446
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
447
+ let py = slf.py();
448
+ let state = [
449
+ slf.bucket.clone().into_pyobject(py)?.into_any(),
450
+ slf.key.clone().into_pyobject(py)?.into_any(),
451
+ slf.content.clone().into_pyobject(py)?.into_any(),
452
+ ];
453
+ PyTuple::new(py, state)
454
+ }
397
455
  }
398
456
 
399
- #[pyclass(name = "PutObjectFromFileInput")]
457
+ #[pyclass(name = "PutObjectFromFileInput", module = "tosnativeclient")]
400
458
  pub struct PutObjectFromFileInput {
401
459
  #[pyo3(get, set)]
402
460
  pub(crate) bucket: String,
@@ -417,9 +475,18 @@ impl PutObjectFromFileInput {
417
475
  file_path: file_path.to_string(),
418
476
  })
419
477
  }
478
+ pub fn __getnewargs__(slf: PyRef<'_, Self>) -> PyResult<Bound<'_, PyTuple>> {
479
+ let py = slf.py();
480
+ let state = [
481
+ slf.bucket.clone().into_pyobject(py)?.into_any(),
482
+ slf.key.clone().into_pyobject(py)?.into_any(),
483
+ slf.file_path.clone().into_pyobject(py)?.into_any(),
484
+ ];
485
+ PyTuple::new(py, state)
486
+ }
420
487
  }
421
488
 
422
- #[pyclass(name = "PutObjectOutput")]
489
+ #[pyclass(name = "PutObjectOutput", module = "tosnativeclient")]
423
490
  pub struct PutObjectOutput {
424
491
  #[pyo3(get)]
425
492
  pub(crate) request_id: String,
@@ -2,7 +2,8 @@ use crate::tos_client::InnerTosClient;
2
2
  use crate::tos_error::map_tos_error;
3
3
  use async_channel::{Receiver, Sender};
4
4
  use futures_util::future::join_all;
5
- use pyo3::{pyclass, pymethods, PyRefMut, PyResult};
5
+ use pyo3::types::PyTuple;
6
+ use pyo3::{pyclass, pymethods, Bound, IntoPyObject, PyRef, PyRefMut, PyResult};
6
7
  use std::collections::HashMap;
7
8
  use std::sync::atomic::{AtomicI8, AtomicIsize, Ordering};
8
9
  use std::sync::Arc;
@@ -29,7 +30,7 @@ const MAX_PART_NUMBER: isize = 10000;
29
30
  const OTHER_MU_KICK_OFF: i8 = 1;
30
31
  const RELEASE_MU_KICK_OFF: i8 = 2;
31
32
 
32
- #[pyclass(name = "WriteStream")]
33
+ #[pyclass(name = "WriteStream", module = "tosnativeclient")]
33
34
  pub struct WriteStream {
34
35
  object_writer: Arc<ObjectWriter>,
35
36
  runtime: Arc<Runtime>,
@@ -93,8 +94,15 @@ impl WriteStream {
93
94
  let _key = key.clone();
94
95
  let _storage_class = storage_class.clone();
95
96
 
96
- let object_writer =
97
- ObjectWriter::new(client, _bucket, _key, _storage_class, part_size).await?;
97
+ let object_writer = ObjectWriter::new(
98
+ client,
99
+ runtime.clone(),
100
+ _bucket,
101
+ _key,
102
+ _storage_class,
103
+ part_size,
104
+ )
105
+ .await?;
98
106
  Ok(Self {
99
107
  object_writer: Arc::new(object_writer),
100
108
  runtime,
@@ -134,6 +142,7 @@ struct ObjectWriter {
134
142
  impl ObjectWriter {
135
143
  async fn new(
136
144
  client: Arc<InnerTosClient>,
145
+ runtime: Arc<Runtime>,
137
146
  bucket: String,
138
147
  key: String,
139
148
  storage_class: Option<String>,
@@ -144,7 +153,15 @@ impl ObjectWriter {
144
153
  key,
145
154
  storage_class,
146
155
  });
147
- let ou = ObjectUploader::new(client, wp, part_size, 0, Arc::new(AtomicI8::new(0))).await?;
156
+ let ou = ObjectUploader::new(
157
+ client,
158
+ runtime,
159
+ wp,
160
+ part_size,
161
+ 0,
162
+ Arc::new(AtomicI8::new(0)),
163
+ )
164
+ .await?;
148
165
  Ok(Self {
149
166
  ctx: Mutex::new((ou, 0)),
150
167
  closed: Arc::new(AtomicI8::new(0)),
@@ -263,6 +280,7 @@ struct WriteParam {
263
280
  struct ObjectUploader {
264
281
  next_write_offset: isize,
265
282
  uc: Arc<UploadContext>,
283
+ runtime: Arc<Runtime>,
266
284
  current: Option<Part>,
267
285
  part_size: isize,
268
286
  max_size: isize,
@@ -277,6 +295,7 @@ struct ObjectUploader {
277
295
  impl ObjectUploader {
278
296
  async fn new(
279
297
  client: Arc<InnerTosClient>,
298
+ runtime: Arc<Runtime>,
280
299
  wp: Arc<WriteParam>,
281
300
  part_size: isize,
282
301
  next_write_offset: isize,
@@ -293,6 +312,7 @@ impl ObjectUploader {
293
312
  let mut ou = Self {
294
313
  next_write_offset,
295
314
  uc: Arc::new(UploadContext::new(created, wp, client)),
315
+ runtime,
296
316
  current: None,
297
317
  part_size,
298
318
  max_size,
@@ -474,7 +494,7 @@ impl ObjectUploader {
474
494
  let dp = self.dp.clone();
475
495
  let st = self.st.clone();
476
496
  let uc = self.uc.clone();
477
- self.wait_dispatch = Some(Handle::current().spawn(async move {
497
+ self.wait_dispatch = Some(self.runtime.spawn(async move {
478
498
  loop {
479
499
  match dp.pull().await {
480
500
  None => return,
@@ -499,12 +519,13 @@ impl ObjectUploader {
499
519
  }
500
520
 
501
521
  async fn execute(&mut self) {
522
+ let runtime = self.runtime.clone();
502
523
  let dp = self.dp.clone();
503
524
  let st = self.st.clone();
504
525
  let ta = self.ta.clone();
505
526
  let uc = self.uc.clone();
506
527
  let mu_ctx = self.mu_ctx.clone();
507
- self.wait_execute = Some(Handle::current().spawn(async move {
528
+ self.wait_execute = Some(self.runtime.spawn(async move {
508
529
  let mut wait_async_uploads = Vec::with_capacity(16);
509
530
  loop {
510
531
  match st.pull().await {
@@ -518,6 +539,7 @@ impl ObjectUploader {
518
539
  wait_async_uploads.push(
519
540
  uc.clone()
520
541
  .async_upload(
542
+ runtime.clone(),
521
543
  dp.clone(),
522
544
  st.clone(),
523
545
  ta.clone(),
@@ -589,6 +611,7 @@ impl UploadContext {
589
611
 
590
612
  async fn async_upload(
591
613
  self: Arc<Self>,
614
+ runtime: Arc<Runtime>,
592
615
  dp: Arc<Dispatcher>,
593
616
  st: Arc<Store>,
594
617
  ta: Arc<TokenAcquirer>,
@@ -596,7 +619,7 @@ impl UploadContext {
596
619
  mut si: StoreItem,
597
620
  ) -> JoinHandle<()> {
598
621
  let aborted = self.aborted.clone();
599
- Handle::current().spawn(async move {
622
+ runtime.spawn(async move {
600
623
  let _ = ta.acquire().await;
601
624
  if aborted.load(Ordering::Acquire) == 1 {
602
625
  si.release();