1use crate::err::{self, DowncastError, PyErr, PyResult};
2use crate::exceptions::PyTypeError;
3use crate::ffi_ptr_ext::FfiPtrExt;
4#[cfg(feature = "experimental-inspect")]
5use crate::inspect::types::TypeInfo;
6use crate::instance::Bound;
7use crate::internal_tricks::get_ssize_index;
8use crate::py_result_ext::PyResultExt;
9use crate::sync::PyOnceLock;
10use crate::type_object::PyTypeInfo;
11use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType};
12use crate::{
13 ffi, Borrowed, BoundObject, FromPyObject, IntoPyObject, IntoPyObjectExt, Py, PyTypeCheck,
14 Python,
15};
16
17#[repr(transparent)]
25pub struct PySequence(PyAny);
26pyobject_native_type_named!(PySequence);
27
28impl PySequence {
29 pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
33 let ty = T::type_object(py);
34 get_sequence_abc(py)?.call_method1("register", (ty,))?;
35 Ok(())
36 }
37}
38
39#[doc(alias = "PySequence")]
45pub trait PySequenceMethods<'py>: crate::sealed::Sealed {
46 fn len(&self) -> PyResult<usize>;
50
51 fn is_empty(&self) -> PyResult<bool>;
53
54 fn concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>>;
58
59 fn repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>>;
63
64 fn in_place_concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>>;
72
73 fn in_place_repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>>;
81
82 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
86
87 fn get_slice(&self, begin: usize, end: usize) -> PyResult<Bound<'py, PySequence>>;
91
92 fn set_item<I>(&self, i: usize, item: I) -> PyResult<()>
96 where
97 I: IntoPyObject<'py>;
98
99 fn del_item(&self, i: usize) -> PyResult<()>;
103
104 fn set_slice(&self, i1: usize, i2: usize, v: &Bound<'_, PyAny>) -> PyResult<()>;
108
109 fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()>;
113
114 #[cfg(not(PyPy))]
117 fn count<V>(&self, value: V) -> PyResult<usize>
118 where
119 V: IntoPyObject<'py>;
120
121 fn contains<V>(&self, value: V) -> PyResult<bool>
125 where
126 V: IntoPyObject<'py>;
127
128 fn index<V>(&self, value: V) -> PyResult<usize>
132 where
133 V: IntoPyObject<'py>;
134
135 fn to_list(&self) -> PyResult<Bound<'py, PyList>>;
137
138 fn to_tuple(&self) -> PyResult<Bound<'py, PyTuple>>;
140}
141
142impl<'py> PySequenceMethods<'py> for Bound<'py, PySequence> {
143 #[inline]
144 fn len(&self) -> PyResult<usize> {
145 let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
146 crate::err::error_on_minusone(self.py(), v)?;
147 Ok(v as usize)
148 }
149
150 #[inline]
151 fn is_empty(&self) -> PyResult<bool> {
152 self.len().map(|l| l == 0)
153 }
154
155 #[inline]
156 fn concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>> {
157 unsafe {
158 ffi::PySequence_Concat(self.as_ptr(), other.as_ptr())
159 .assume_owned_or_err(self.py())
160 .cast_into_unchecked()
161 }
162 }
163
164 #[inline]
165 fn repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>> {
166 unsafe {
167 ffi::PySequence_Repeat(self.as_ptr(), get_ssize_index(count))
168 .assume_owned_or_err(self.py())
169 .cast_into_unchecked()
170 }
171 }
172
173 #[inline]
174 fn in_place_concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>> {
175 unsafe {
176 ffi::PySequence_InPlaceConcat(self.as_ptr(), other.as_ptr())
177 .assume_owned_or_err(self.py())
178 .cast_into_unchecked()
179 }
180 }
181
182 #[inline]
183 fn in_place_repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>> {
184 unsafe {
185 ffi::PySequence_InPlaceRepeat(self.as_ptr(), get_ssize_index(count))
186 .assume_owned_or_err(self.py())
187 .cast_into_unchecked()
188 }
189 }
190
191 #[inline]
192 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
193 unsafe {
194 ffi::PySequence_GetItem(self.as_ptr(), get_ssize_index(index))
195 .assume_owned_or_err(self.py())
196 }
197 }
198
199 #[inline]
200 fn get_slice(&self, begin: usize, end: usize) -> PyResult<Bound<'py, PySequence>> {
201 unsafe {
202 ffi::PySequence_GetSlice(self.as_ptr(), get_ssize_index(begin), get_ssize_index(end))
203 .assume_owned_or_err(self.py())
204 .cast_into_unchecked()
205 }
206 }
207
208 #[inline]
209 fn set_item<I>(&self, i: usize, item: I) -> PyResult<()>
210 where
211 I: IntoPyObject<'py>,
212 {
213 fn inner(
214 seq: &Bound<'_, PySequence>,
215 i: usize,
216 item: Borrowed<'_, '_, PyAny>,
217 ) -> PyResult<()> {
218 err::error_on_minusone(seq.py(), unsafe {
219 ffi::PySequence_SetItem(seq.as_ptr(), get_ssize_index(i), item.as_ptr())
220 })
221 }
222
223 let py = self.py();
224 inner(
225 self,
226 i,
227 item.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
228 )
229 }
230
231 #[inline]
232 fn del_item(&self, i: usize) -> PyResult<()> {
233 err::error_on_minusone(self.py(), unsafe {
234 ffi::PySequence_DelItem(self.as_ptr(), get_ssize_index(i))
235 })
236 }
237
238 #[inline]
239 fn set_slice(&self, i1: usize, i2: usize, v: &Bound<'_, PyAny>) -> PyResult<()> {
240 err::error_on_minusone(self.py(), unsafe {
241 ffi::PySequence_SetSlice(
242 self.as_ptr(),
243 get_ssize_index(i1),
244 get_ssize_index(i2),
245 v.as_ptr(),
246 )
247 })
248 }
249
250 #[inline]
251 fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> {
252 err::error_on_minusone(self.py(), unsafe {
253 ffi::PySequence_DelSlice(self.as_ptr(), get_ssize_index(i1), get_ssize_index(i2))
254 })
255 }
256
257 #[inline]
258 #[cfg(not(PyPy))]
259 fn count<V>(&self, value: V) -> PyResult<usize>
260 where
261 V: IntoPyObject<'py>,
262 {
263 fn inner(seq: &Bound<'_, PySequence>, value: Borrowed<'_, '_, PyAny>) -> PyResult<usize> {
264 let r = unsafe { ffi::PySequence_Count(seq.as_ptr(), value.as_ptr()) };
265 crate::err::error_on_minusone(seq.py(), r)?;
266 Ok(r as usize)
267 }
268
269 let py = self.py();
270 inner(
271 self,
272 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
273 )
274 }
275
276 #[inline]
277 fn contains<V>(&self, value: V) -> PyResult<bool>
278 where
279 V: IntoPyObject<'py>,
280 {
281 fn inner(seq: &Bound<'_, PySequence>, value: Borrowed<'_, '_, PyAny>) -> PyResult<bool> {
282 let r = unsafe { ffi::PySequence_Contains(seq.as_ptr(), value.as_ptr()) };
283 match r {
284 0 => Ok(false),
285 1 => Ok(true),
286 _ => Err(PyErr::fetch(seq.py())),
287 }
288 }
289
290 let py = self.py();
291 inner(
292 self,
293 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
294 )
295 }
296
297 #[inline]
298 fn index<V>(&self, value: V) -> PyResult<usize>
299 where
300 V: IntoPyObject<'py>,
301 {
302 fn inner(seq: &Bound<'_, PySequence>, value: Borrowed<'_, '_, PyAny>) -> PyResult<usize> {
303 let r = unsafe { ffi::PySequence_Index(seq.as_ptr(), value.as_ptr()) };
304 crate::err::error_on_minusone(seq.py(), r)?;
305 Ok(r as usize)
306 }
307
308 let py = self.py();
309 inner(
310 self,
311 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
312 )
313 }
314
315 #[inline]
316 fn to_list(&self) -> PyResult<Bound<'py, PyList>> {
317 unsafe {
318 ffi::PySequence_List(self.as_ptr())
319 .assume_owned_or_err(self.py())
320 .cast_into_unchecked()
321 }
322 }
323
324 #[inline]
325 fn to_tuple(&self) -> PyResult<Bound<'py, PyTuple>> {
326 unsafe {
327 ffi::PySequence_Tuple(self.as_ptr())
328 .assume_owned_or_err(self.py())
329 .cast_into_unchecked()
330 }
331 }
332}
333
334impl<'py, T> FromPyObject<'py> for Vec<T>
335where
336 T: FromPyObject<'py>,
337{
338 fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
339 if obj.is_instance_of::<PyString>() {
340 return Err(PyTypeError::new_err("Can't extract `str` to `Vec`"));
341 }
342 extract_sequence(obj)
343 }
344
345 #[cfg(feature = "experimental-inspect")]
346 fn type_input() -> TypeInfo {
347 TypeInfo::sequence_of(T::type_input())
348 }
349}
350
351fn extract_sequence<'py, T>(obj: &Bound<'py, PyAny>) -> PyResult<Vec<T>>
352where
353 T: FromPyObject<'py>,
354{
355 let seq = unsafe {
358 if ffi::PySequence_Check(obj.as_ptr()) != 0 {
359 obj.cast_unchecked::<PySequence>()
360 } else {
361 return Err(DowncastError::new(obj, "Sequence").into());
362 }
363 };
364
365 let mut v = Vec::with_capacity(seq.len().unwrap_or(0));
366 for item in seq.try_iter()? {
367 v.push(item?.extract::<T>()?);
368 }
369 Ok(v)
370}
371
372fn get_sequence_abc(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
373 static SEQUENCE_ABC: PyOnceLock<Py<PyType>> = PyOnceLock::new();
374
375 SEQUENCE_ABC.import(py, "collections.abc", "Sequence")
376}
377
378impl PyTypeCheck for PySequence {
379 const NAME: &'static str = "Sequence";
380 #[cfg(feature = "experimental-inspect")]
381 const PYTHON_TYPE: &'static str = "collections.abc.Sequence";
382
383 #[inline]
384 fn type_check(object: &Bound<'_, PyAny>) -> bool {
385 PyList::is_type_of(object)
388 || PyTuple::is_type_of(object)
389 || get_sequence_abc(object.py())
390 .and_then(|abc| object.is_instance(abc))
391 .unwrap_or_else(|err| {
392 err.write_unraisable(object.py(), Some(object));
393 false
394 })
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use crate::types::{PyAnyMethods, PyList, PySequence, PySequenceMethods, PyTuple};
401 use crate::{ffi, IntoPyObject, Py, PyAny, Python};
402 use std::ptr;
403
404 fn get_object() -> Py<PyAny> {
405 Python::attach(|py| {
407 let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
408
409 obj.into_pyobject(py).unwrap().unbind()
410 })
411 }
412
413 #[test]
414 fn test_numbers_are_not_sequences() {
415 Python::attach(|py| {
416 let v = 42i32;
417 assert!(v.into_pyobject(py).unwrap().cast::<PySequence>().is_err());
418 });
419 }
420
421 #[test]
422 fn test_strings_are_sequences() {
423 Python::attach(|py| {
424 let v = "London Calling";
425 assert!(v.into_pyobject(py).unwrap().cast::<PySequence>().is_ok());
426 });
427 }
428
429 #[test]
430 fn test_strings_cannot_be_extracted_to_vec() {
431 Python::attach(|py| {
432 let v = "London Calling";
433 let ob = v.into_pyobject(py).unwrap();
434
435 assert!(ob.extract::<Vec<String>>().is_err());
436 assert!(ob.extract::<Vec<char>>().is_err());
437 });
438 }
439
440 #[test]
441 fn test_seq_empty() {
442 Python::attach(|py| {
443 let v: Vec<i32> = vec![];
444 let ob = v.into_pyobject(py).unwrap();
445 let seq = ob.cast::<PySequence>().unwrap();
446 assert_eq!(0, seq.len().unwrap());
447
448 let needle = 7i32.into_pyobject(py).unwrap();
449 assert!(!seq.contains(&needle).unwrap());
450 });
451 }
452
453 #[test]
454 fn test_seq_is_empty() {
455 Python::attach(|py| {
456 let list = vec![1].into_pyobject(py).unwrap();
457 let seq = list.cast::<PySequence>().unwrap();
458 assert!(!seq.is_empty().unwrap());
459 let vec: Vec<u32> = Vec::new();
460 let empty_list = vec.into_pyobject(py).unwrap();
461 let empty_seq = empty_list.cast::<PySequence>().unwrap();
462 assert!(empty_seq.is_empty().unwrap());
463 });
464 }
465
466 #[test]
467 fn test_seq_contains() {
468 Python::attach(|py| {
469 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
470 let ob = v.into_pyobject(py).unwrap();
471 let seq = ob.cast::<PySequence>().unwrap();
472 assert_eq!(6, seq.len().unwrap());
473
474 let bad_needle = 7i32.into_pyobject(py).unwrap();
475 assert!(!seq.contains(&bad_needle).unwrap());
476
477 let good_needle = 8i32.into_pyobject(py).unwrap();
478 assert!(seq.contains(&good_needle).unwrap());
479
480 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
481 assert!(seq.contains(&type_coerced_needle).unwrap());
482 });
483 }
484
485 #[test]
486 fn test_seq_get_item() {
487 Python::attach(|py| {
488 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
489 let ob = v.into_pyobject(py).unwrap();
490 let seq = ob.cast::<PySequence>().unwrap();
491 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
492 assert_eq!(1, seq.get_item(1).unwrap().extract::<i32>().unwrap());
493 assert_eq!(2, seq.get_item(2).unwrap().extract::<i32>().unwrap());
494 assert_eq!(3, seq.get_item(3).unwrap().extract::<i32>().unwrap());
495 assert_eq!(5, seq.get_item(4).unwrap().extract::<i32>().unwrap());
496 assert_eq!(8, seq.get_item(5).unwrap().extract::<i32>().unwrap());
497 assert!(seq.get_item(10).is_err());
498 });
499 }
500
501 #[test]
502 fn test_seq_del_item() {
503 Python::attach(|py| {
504 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
505 let ob = v.into_pyobject(py).unwrap();
506 let seq = ob.cast::<PySequence>().unwrap();
507 assert!(seq.del_item(10).is_err());
508 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
509 assert!(seq.del_item(0).is_ok());
510 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
511 assert!(seq.del_item(0).is_ok());
512 assert_eq!(2, seq.get_item(0).unwrap().extract::<i32>().unwrap());
513 assert!(seq.del_item(0).is_ok());
514 assert_eq!(3, seq.get_item(0).unwrap().extract::<i32>().unwrap());
515 assert!(seq.del_item(0).is_ok());
516 assert_eq!(5, seq.get_item(0).unwrap().extract::<i32>().unwrap());
517 assert!(seq.del_item(0).is_ok());
518 assert_eq!(8, seq.get_item(0).unwrap().extract::<i32>().unwrap());
519 assert!(seq.del_item(0).is_ok());
520 assert_eq!(0, seq.len().unwrap());
521 assert!(seq.del_item(0).is_err());
522 });
523 }
524
525 #[test]
526 fn test_seq_set_item() {
527 Python::attach(|py| {
528 let v: Vec<i32> = vec![1, 2];
529 let ob = v.into_pyobject(py).unwrap();
530 let seq = ob.cast::<PySequence>().unwrap();
531 assert_eq!(2, seq.get_item(1).unwrap().extract::<i32>().unwrap());
532 assert!(seq.set_item(1, 10).is_ok());
533 assert_eq!(10, seq.get_item(1).unwrap().extract::<i32>().unwrap());
534 });
535 }
536
537 #[test]
538 fn test_seq_set_item_refcnt() {
539 let obj = get_object();
540
541 Python::attach(|py| {
542 let v: Vec<i32> = vec![1, 2];
543 let ob = v.into_pyobject(py).unwrap();
544 let seq = ob.cast::<PySequence>().unwrap();
545 assert!(seq.set_item(1, &obj).is_ok());
546 assert!(ptr::eq(seq.get_item(1).unwrap().as_ptr(), obj.as_ptr()));
547 });
548
549 Python::attach(move |py| {
550 assert_eq!(1, obj.get_refcnt(py));
551 });
552 }
553
554 #[test]
555 fn test_seq_get_slice() {
556 Python::attach(|py| {
557 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
558 let ob = v.into_pyobject(py).unwrap();
559 let seq = ob.cast::<PySequence>().unwrap();
560 assert_eq!(
561 [1, 2, 3],
562 seq.get_slice(1, 4).unwrap().extract::<[i32; 3]>().unwrap()
563 );
564 assert_eq!(
565 [3, 5, 8],
566 seq.get_slice(3, 100)
567 .unwrap()
568 .extract::<[i32; 3]>()
569 .unwrap()
570 );
571 });
572 }
573
574 #[test]
575 fn test_set_slice() {
576 Python::attach(|py| {
577 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
578 let w: Vec<i32> = vec![7, 4];
579 let ob = v.into_pyobject(py).unwrap();
580 let seq = ob.cast::<PySequence>().unwrap();
581 let ins = w.into_pyobject(py).unwrap();
582 seq.set_slice(1, 4, &ins).unwrap();
583 assert_eq!([1, 7, 4, 5, 8], seq.extract::<[i32; 5]>().unwrap());
584 seq.set_slice(3, 100, &PyList::empty(py)).unwrap();
585 assert_eq!([1, 7, 4], seq.extract::<[i32; 3]>().unwrap());
586 });
587 }
588
589 #[test]
590 fn test_del_slice() {
591 Python::attach(|py| {
592 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
593 let ob = v.into_pyobject(py).unwrap();
594 let seq = ob.cast::<PySequence>().unwrap();
595 seq.del_slice(1, 4).unwrap();
596 assert_eq!([1, 5, 8], seq.extract::<[i32; 3]>().unwrap());
597 seq.del_slice(1, 100).unwrap();
598 assert_eq!([1], seq.extract::<[i32; 1]>().unwrap());
599 });
600 }
601
602 #[test]
603 fn test_seq_index() {
604 Python::attach(|py| {
605 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
606 let ob = v.into_pyobject(py).unwrap();
607 let seq = ob.cast::<PySequence>().unwrap();
608 assert_eq!(0, seq.index(1i32).unwrap());
609 assert_eq!(2, seq.index(2i32).unwrap());
610 assert_eq!(3, seq.index(3i32).unwrap());
611 assert_eq!(4, seq.index(5i32).unwrap());
612 assert_eq!(5, seq.index(8i32).unwrap());
613 assert!(seq.index(42i32).is_err());
614 });
615 }
616
617 #[test]
618 #[cfg(not(any(PyPy, GraalPy)))]
619 fn test_seq_count() {
620 Python::attach(|py| {
621 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
622 let ob = v.into_pyobject(py).unwrap();
623 let seq = ob.cast::<PySequence>().unwrap();
624 assert_eq!(2, seq.count(1i32).unwrap());
625 assert_eq!(1, seq.count(2i32).unwrap());
626 assert_eq!(1, seq.count(3i32).unwrap());
627 assert_eq!(1, seq.count(5i32).unwrap());
628 assert_eq!(1, seq.count(8i32).unwrap());
629 assert_eq!(0, seq.count(42i32).unwrap());
630 });
631 }
632
633 #[test]
634 fn test_seq_iter() {
635 Python::attach(|py| {
636 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
637 let ob = (&v).into_pyobject(py).unwrap();
638 let seq = ob.cast::<PySequence>().unwrap();
639 let mut idx = 0;
640 for el in seq.try_iter().unwrap() {
641 assert_eq!(v[idx], el.unwrap().extract::<i32>().unwrap());
642 idx += 1;
643 }
644 assert_eq!(idx, v.len());
645 });
646 }
647
648 #[test]
649 fn test_seq_strings() {
650 Python::attach(|py| {
651 let v = vec!["It", "was", "the", "worst", "of", "times"];
652 let ob = v.into_pyobject(py).unwrap();
653 let seq = ob.cast::<PySequence>().unwrap();
654
655 let bad_needle = "blurst".into_pyobject(py).unwrap();
656 assert!(!seq.contains(bad_needle).unwrap());
657
658 let good_needle = "worst".into_pyobject(py).unwrap();
659 assert!(seq.contains(good_needle).unwrap());
660 });
661 }
662
663 #[test]
664 fn test_seq_concat() {
665 Python::attach(|py| {
666 let v: Vec<i32> = vec![1, 2, 3];
667 let ob = v.into_pyobject(py).unwrap();
668 let seq = ob.cast::<PySequence>().unwrap();
669 let concat_seq = seq.concat(seq).unwrap();
670 assert_eq!(6, concat_seq.len().unwrap());
671 let concat_v: Vec<i32> = vec![1, 2, 3, 1, 2, 3];
672 for (el, cc) in concat_seq.try_iter().unwrap().zip(concat_v) {
673 assert_eq!(cc, el.unwrap().extract::<i32>().unwrap());
674 }
675 });
676 }
677
678 #[test]
679 fn test_seq_concat_string() {
680 Python::attach(|py| {
681 let v = "string";
682 let ob = v.into_pyobject(py).unwrap();
683 let seq = ob.cast::<PySequence>().unwrap();
684 let concat_seq = seq.concat(seq).unwrap();
685 assert_eq!(12, concat_seq.len().unwrap());
686 let concat_v = "stringstring".to_owned();
687 for (el, cc) in seq.try_iter().unwrap().zip(concat_v.chars()) {
688 assert_eq!(cc, el.unwrap().extract::<char>().unwrap());
689 }
690 });
691 }
692
693 #[test]
694 fn test_seq_repeat() {
695 Python::attach(|py| {
696 let v = vec!["foo", "bar"];
697 let ob = v.into_pyobject(py).unwrap();
698 let seq = ob.cast::<PySequence>().unwrap();
699 let repeat_seq = seq.repeat(3).unwrap();
700 assert_eq!(6, repeat_seq.len().unwrap());
701 let repeated = ["foo", "bar", "foo", "bar", "foo", "bar"];
702 for (el, rpt) in repeat_seq.try_iter().unwrap().zip(repeated.iter()) {
703 assert_eq!(*rpt, el.unwrap().extract::<String>().unwrap());
704 }
705 });
706 }
707
708 #[test]
709 fn test_seq_inplace() {
710 Python::attach(|py| {
711 let v = vec!["foo", "bar"];
712 let ob = v.into_pyobject(py).unwrap();
713 let seq = ob.cast::<PySequence>().unwrap();
714 let rep_seq = seq.in_place_repeat(3).unwrap();
715 assert_eq!(6, seq.len().unwrap());
716 assert!(seq.is(&rep_seq));
717
718 let conc_seq = seq.in_place_concat(seq).unwrap();
719 assert_eq!(12, seq.len().unwrap());
720 assert!(seq.is(&conc_seq));
721 });
722 }
723
724 #[test]
725 fn test_list_coercion() {
726 Python::attach(|py| {
727 let v = vec!["foo", "bar"];
728 let ob = (&v).into_pyobject(py).unwrap();
729 let seq = ob.cast::<PySequence>().unwrap();
730 assert!(seq
731 .to_list()
732 .unwrap()
733 .eq(PyList::new(py, &v).unwrap())
734 .unwrap());
735 });
736 }
737
738 #[test]
739 fn test_strings_coerce_to_lists() {
740 Python::attach(|py| {
741 let v = "foo";
742 let ob = v.into_pyobject(py).unwrap();
743 let seq = ob.cast::<PySequence>().unwrap();
744 assert!(seq
745 .to_list()
746 .unwrap()
747 .eq(PyList::new(py, ["f", "o", "o"]).unwrap())
748 .unwrap());
749 });
750 }
751
752 #[test]
753 fn test_tuple_coercion() {
754 Python::attach(|py| {
755 let v = ("foo", "bar");
756 let ob = v.into_pyobject(py).unwrap();
757 let seq = ob.cast::<PySequence>().unwrap();
758 assert!(seq
759 .to_tuple()
760 .unwrap()
761 .eq(PyTuple::new(py, ["foo", "bar"]).unwrap())
762 .unwrap());
763 });
764 }
765
766 #[test]
767 fn test_lists_coerce_to_tuples() {
768 Python::attach(|py| {
769 let v = vec!["foo", "bar"];
770 let ob = (&v).into_pyobject(py).unwrap();
771 let seq = ob.cast::<PySequence>().unwrap();
772 assert!(seq
773 .to_tuple()
774 .unwrap()
775 .eq(PyTuple::new(py, &v).unwrap())
776 .unwrap());
777 });
778 }
779
780 #[test]
781 fn test_extract_tuple_to_vec() {
782 Python::attach(|py| {
783 let v: Vec<i32> = py
784 .eval(ffi::c_str!("(1, 2)"), None, None)
785 .unwrap()
786 .extract()
787 .unwrap();
788 assert!(v == [1, 2]);
789 });
790 }
791
792 #[test]
793 fn test_extract_range_to_vec() {
794 Python::attach(|py| {
795 let v: Vec<i32> = py
796 .eval(ffi::c_str!("range(1, 5)"), None, None)
797 .unwrap()
798 .extract()
799 .unwrap();
800 assert!(v == [1, 2, 3, 4]);
801 });
802 }
803
804 #[test]
805 fn test_extract_bytearray_to_vec() {
806 Python::attach(|py| {
807 let v: Vec<u8> = py
808 .eval(ffi::c_str!("bytearray(b'abc')"), None, None)
809 .unwrap()
810 .extract()
811 .unwrap();
812 assert!(v == b"abc");
813 });
814 }
815
816 #[test]
817 fn test_seq_cast_unchecked() {
818 Python::attach(|py| {
819 let v = vec!["foo", "bar"];
820 let ob = v.into_pyobject(py).unwrap();
821 let seq = ob.cast::<PySequence>().unwrap();
822 let type_ptr = seq.as_any();
823 let seq_from = unsafe { type_ptr.cast_unchecked::<PySequence>() };
824 assert!(seq_from.to_list().is_ok());
825 });
826 }
827}