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::GILOnceCell;
10use crate::type_object::PyTypeInfo;
11use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType};
12#[cfg(feature = "gil-refs")]
13use crate::{err::PyDowncastError, PyNativeType};
14use crate::{ffi, FromPyObject, Py, PyTypeCheck, Python, ToPyObject};
15
16#[repr(transparent)]
24pub struct PySequence(PyAny);
25pyobject_native_type_named!(PySequence);
26pyobject_native_type_extract!(PySequence);
27
28impl PySequence {
29 pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
33 let ty = T::type_object_bound(py);
34 get_sequence_abc(py)?.call_method1("register", (ty,))?;
35 Ok(())
36 }
37}
38
39#[cfg(feature = "gil-refs")]
40impl PySequence {
41 #[inline]
45 pub fn len(&self) -> PyResult<usize> {
46 self.as_borrowed().len()
47 }
48
49 #[inline]
51 pub fn is_empty(&self) -> PyResult<bool> {
52 self.as_borrowed().is_empty()
53 }
54
55 #[inline]
59 pub fn concat(&self, other: &PySequence) -> PyResult<&PySequence> {
60 self.as_borrowed()
61 .concat(&other.as_borrowed())
62 .map(Bound::into_gil_ref)
63 }
64
65 #[inline]
69 pub fn repeat(&self, count: usize) -> PyResult<&PySequence> {
70 self.as_borrowed().repeat(count).map(Bound::into_gil_ref)
71 }
72
73 #[inline]
81 pub fn in_place_concat(&self, other: &PySequence) -> PyResult<&PySequence> {
82 self.as_borrowed()
83 .in_place_concat(&other.as_borrowed())
84 .map(Bound::into_gil_ref)
85 }
86
87 #[inline]
95 pub fn in_place_repeat(&self, count: usize) -> PyResult<&PySequence> {
96 self.as_borrowed()
97 .in_place_repeat(count)
98 .map(Bound::into_gil_ref)
99 }
100
101 #[inline]
105 pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
106 self.as_borrowed().get_item(index).map(Bound::into_gil_ref)
107 }
108
109 #[inline]
113 pub fn get_slice(&self, begin: usize, end: usize) -> PyResult<&PySequence> {
114 self.as_borrowed()
115 .get_slice(begin, end)
116 .map(Bound::into_gil_ref)
117 }
118
119 #[inline]
123 pub fn set_item<I>(&self, i: usize, item: I) -> PyResult<()>
124 where
125 I: ToPyObject,
126 {
127 self.as_borrowed().set_item(i, item)
128 }
129
130 #[inline]
134 pub fn del_item(&self, i: usize) -> PyResult<()> {
135 self.as_borrowed().del_item(i)
136 }
137
138 #[inline]
142 pub fn set_slice(&self, i1: usize, i2: usize, v: &PyAny) -> PyResult<()> {
143 self.as_borrowed().set_slice(i1, i2, &v.as_borrowed())
144 }
145
146 #[inline]
150 pub fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> {
151 self.as_borrowed().del_slice(i1, i2)
152 }
153
154 #[inline]
157 #[cfg(not(any(PyPy, GraalPy)))]
158 pub fn count<V>(&self, value: V) -> PyResult<usize>
159 where
160 V: ToPyObject,
161 {
162 self.as_borrowed().count(value)
163 }
164
165 #[inline]
169 pub fn contains<V>(&self, value: V) -> PyResult<bool>
170 where
171 V: ToPyObject,
172 {
173 self.as_borrowed().contains(value)
174 }
175
176 #[inline]
180 pub fn index<V>(&self, value: V) -> PyResult<usize>
181 where
182 V: ToPyObject,
183 {
184 self.as_borrowed().index(value)
185 }
186
187 #[inline]
189 pub fn to_list(&self) -> PyResult<&PyList> {
190 self.as_borrowed().to_list().map(Bound::into_gil_ref)
191 }
192
193 #[inline]
195 pub fn to_tuple(&self) -> PyResult<&PyTuple> {
196 self.as_borrowed().to_tuple().map(Bound::into_gil_ref)
197 }
198}
199
200#[doc(alias = "PySequence")]
206pub trait PySequenceMethods<'py>: crate::sealed::Sealed {
207 fn len(&self) -> PyResult<usize>;
211
212 fn is_empty(&self) -> PyResult<bool>;
214
215 fn concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>>;
219
220 fn repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>>;
224
225 fn in_place_concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>>;
233
234 fn in_place_repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>>;
242
243 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
247
248 fn get_slice(&self, begin: usize, end: usize) -> PyResult<Bound<'py, PySequence>>;
252
253 fn set_item<I>(&self, i: usize, item: I) -> PyResult<()>
257 where
258 I: ToPyObject;
259
260 fn del_item(&self, i: usize) -> PyResult<()>;
264
265 fn set_slice(&self, i1: usize, i2: usize, v: &Bound<'_, PyAny>) -> PyResult<()>;
269
270 fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()>;
274
275 #[cfg(not(PyPy))]
278 fn count<V>(&self, value: V) -> PyResult<usize>
279 where
280 V: ToPyObject;
281
282 fn contains<V>(&self, value: V) -> PyResult<bool>
286 where
287 V: ToPyObject;
288
289 fn index<V>(&self, value: V) -> PyResult<usize>
293 where
294 V: ToPyObject;
295
296 fn to_list(&self) -> PyResult<Bound<'py, PyList>>;
298
299 fn to_tuple(&self) -> PyResult<Bound<'py, PyTuple>>;
301}
302
303impl<'py> PySequenceMethods<'py> for Bound<'py, PySequence> {
304 #[inline]
305 fn len(&self) -> PyResult<usize> {
306 let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
307 crate::err::error_on_minusone(self.py(), v)?;
308 Ok(v as usize)
309 }
310
311 #[inline]
312 fn is_empty(&self) -> PyResult<bool> {
313 self.len().map(|l| l == 0)
314 }
315
316 #[inline]
317 fn concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>> {
318 unsafe {
319 ffi::PySequence_Concat(self.as_ptr(), other.as_ptr())
320 .assume_owned_or_err(self.py())
321 .downcast_into_unchecked()
322 }
323 }
324
325 #[inline]
326 fn repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>> {
327 unsafe {
328 ffi::PySequence_Repeat(self.as_ptr(), get_ssize_index(count))
329 .assume_owned_or_err(self.py())
330 .downcast_into_unchecked()
331 }
332 }
333
334 #[inline]
335 fn in_place_concat(&self, other: &Bound<'_, PySequence>) -> PyResult<Bound<'py, PySequence>> {
336 unsafe {
337 ffi::PySequence_InPlaceConcat(self.as_ptr(), other.as_ptr())
338 .assume_owned_or_err(self.py())
339 .downcast_into_unchecked()
340 }
341 }
342
343 #[inline]
344 fn in_place_repeat(&self, count: usize) -> PyResult<Bound<'py, PySequence>> {
345 unsafe {
346 ffi::PySequence_InPlaceRepeat(self.as_ptr(), get_ssize_index(count))
347 .assume_owned_or_err(self.py())
348 .downcast_into_unchecked()
349 }
350 }
351
352 #[inline]
353 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
354 unsafe {
355 ffi::PySequence_GetItem(self.as_ptr(), get_ssize_index(index))
356 .assume_owned_or_err(self.py())
357 }
358 }
359
360 #[inline]
361 fn get_slice(&self, begin: usize, end: usize) -> PyResult<Bound<'py, PySequence>> {
362 unsafe {
363 ffi::PySequence_GetSlice(self.as_ptr(), get_ssize_index(begin), get_ssize_index(end))
364 .assume_owned_or_err(self.py())
365 .downcast_into_unchecked()
366 }
367 }
368
369 #[inline]
370 fn set_item<I>(&self, i: usize, item: I) -> PyResult<()>
371 where
372 I: ToPyObject,
373 {
374 fn inner(seq: &Bound<'_, PySequence>, i: usize, item: Bound<'_, PyAny>) -> PyResult<()> {
375 err::error_on_minusone(seq.py(), unsafe {
376 ffi::PySequence_SetItem(seq.as_ptr(), get_ssize_index(i), item.as_ptr())
377 })
378 }
379
380 let py = self.py();
381 inner(self, i, item.to_object(py).into_bound(py))
382 }
383
384 #[inline]
385 fn del_item(&self, i: usize) -> PyResult<()> {
386 err::error_on_minusone(self.py(), unsafe {
387 ffi::PySequence_DelItem(self.as_ptr(), get_ssize_index(i))
388 })
389 }
390
391 #[inline]
392 fn set_slice(&self, i1: usize, i2: usize, v: &Bound<'_, PyAny>) -> PyResult<()> {
393 err::error_on_minusone(self.py(), unsafe {
394 ffi::PySequence_SetSlice(
395 self.as_ptr(),
396 get_ssize_index(i1),
397 get_ssize_index(i2),
398 v.as_ptr(),
399 )
400 })
401 }
402
403 #[inline]
404 fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> {
405 err::error_on_minusone(self.py(), unsafe {
406 ffi::PySequence_DelSlice(self.as_ptr(), get_ssize_index(i1), get_ssize_index(i2))
407 })
408 }
409
410 #[inline]
411 #[cfg(not(PyPy))]
412 fn count<V>(&self, value: V) -> PyResult<usize>
413 where
414 V: ToPyObject,
415 {
416 fn inner(seq: &Bound<'_, PySequence>, value: Bound<'_, PyAny>) -> PyResult<usize> {
417 let r = unsafe { ffi::PySequence_Count(seq.as_ptr(), value.as_ptr()) };
418 crate::err::error_on_minusone(seq.py(), r)?;
419 Ok(r as usize)
420 }
421
422 let py = self.py();
423 inner(self, value.to_object(py).into_bound(py))
424 }
425
426 #[inline]
427 fn contains<V>(&self, value: V) -> PyResult<bool>
428 where
429 V: ToPyObject,
430 {
431 fn inner(seq: &Bound<'_, PySequence>, value: Bound<'_, PyAny>) -> PyResult<bool> {
432 let r = unsafe { ffi::PySequence_Contains(seq.as_ptr(), value.as_ptr()) };
433 match r {
434 0 => Ok(false),
435 1 => Ok(true),
436 _ => Err(PyErr::fetch(seq.py())),
437 }
438 }
439
440 let py = self.py();
441 inner(self, value.to_object(py).into_bound(py))
442 }
443
444 #[inline]
445 fn index<V>(&self, value: V) -> PyResult<usize>
446 where
447 V: ToPyObject,
448 {
449 fn inner(seq: &Bound<'_, PySequence>, value: Bound<'_, PyAny>) -> PyResult<usize> {
450 let r = unsafe { ffi::PySequence_Index(seq.as_ptr(), value.as_ptr()) };
451 crate::err::error_on_minusone(seq.py(), r)?;
452 Ok(r as usize)
453 }
454
455 let py = self.py();
456 inner(self, value.to_object(self.py()).into_bound(py))
457 }
458
459 #[inline]
460 fn to_list(&self) -> PyResult<Bound<'py, PyList>> {
461 unsafe {
462 ffi::PySequence_List(self.as_ptr())
463 .assume_owned_or_err(self.py())
464 .downcast_into_unchecked()
465 }
466 }
467
468 #[inline]
469 fn to_tuple(&self) -> PyResult<Bound<'py, PyTuple>> {
470 unsafe {
471 ffi::PySequence_Tuple(self.as_ptr())
472 .assume_owned_or_err(self.py())
473 .downcast_into_unchecked()
474 }
475 }
476}
477
478#[inline]
479#[cfg(feature = "gil-refs")]
480fn sequence_len(seq: &PySequence) -> usize {
481 seq.len().expect("failed to get sequence length")
482}
483
484#[inline]
485#[cfg(feature = "gil-refs")]
486fn sequence_slice(seq: &PySequence, start: usize, end: usize) -> &PySequence {
487 seq.get_slice(start, end)
488 .expect("sequence slice operation failed")
489}
490
491#[cfg(feature = "gil-refs")]
492index_impls!(PySequence, "sequence", sequence_len, sequence_slice);
493
494impl<'py, T> FromPyObject<'py> for Vec<T>
495where
496 T: FromPyObject<'py>,
497{
498 fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
499 if obj.is_instance_of::<PyString>() {
500 return Err(PyTypeError::new_err("Can't extract `str` to `Vec`"));
501 }
502 extract_sequence(obj)
503 }
504
505 #[cfg(feature = "experimental-inspect")]
506 fn type_input() -> TypeInfo {
507 TypeInfo::sequence_of(T::type_input())
508 }
509}
510
511fn extract_sequence<'py, T>(obj: &Bound<'py, PyAny>) -> PyResult<Vec<T>>
512where
513 T: FromPyObject<'py>,
514{
515 let seq = unsafe {
518 if ffi::PySequence_Check(obj.as_ptr()) != 0 {
519 obj.downcast_unchecked::<PySequence>()
520 } else {
521 return Err(DowncastError::new(obj, "Sequence").into());
522 }
523 };
524
525 let mut v = Vec::with_capacity(seq.len().unwrap_or(0));
526 for item in seq.iter()? {
527 v.push(item?.extract::<T>()?);
528 }
529 Ok(v)
530}
531
532fn get_sequence_abc(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
533 static SEQUENCE_ABC: GILOnceCell<Py<PyType>> = GILOnceCell::new();
534
535 SEQUENCE_ABC.get_or_try_init_type_ref(py, "collections.abc", "Sequence")
536}
537
538impl PyTypeCheck for PySequence {
539 const NAME: &'static str = "Sequence";
540
541 #[inline]
542 fn type_check(object: &Bound<'_, PyAny>) -> bool {
543 PyList::is_type_of_bound(object)
546 || PyTuple::is_type_of_bound(object)
547 || get_sequence_abc(object.py())
548 .and_then(|abc| object.is_instance(abc))
549 .unwrap_or_else(|err| {
550 err.write_unraisable_bound(object.py(), Some(&object.as_borrowed()));
551 false
552 })
553 }
554}
555
556#[cfg(feature = "gil-refs")]
557#[allow(deprecated)]
558impl<'v> crate::PyTryFrom<'v> for PySequence {
559 fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
563 let value = value.into();
564
565 if PySequence::type_check(&value.as_borrowed()) {
566 unsafe { return Ok(value.downcast_unchecked::<PySequence>()) }
567 }
568
569 Err(PyDowncastError::new(value, "Sequence"))
570 }
571
572 fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
573 value.into().downcast()
574 }
575
576 #[inline]
577 unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PySequence {
578 let ptr = value.into() as *const _ as *const PySequence;
579 &*ptr
580 }
581}
582
583#[cfg(test)]
584mod tests {
585 use crate::types::{PyAnyMethods, PyList, PySequence, PySequenceMethods, PyTuple};
586 use crate::{PyObject, Python, ToPyObject};
587
588 fn get_object() -> PyObject {
589 Python::with_gil(|py| {
591 let obj = py.eval_bound("object()", None, None).unwrap();
592
593 obj.to_object(py)
594 })
595 }
596
597 #[test]
598 fn test_numbers_are_not_sequences() {
599 Python::with_gil(|py| {
600 let v = 42i32;
601 assert!(v.to_object(py).downcast_bound::<PySequence>(py).is_err());
602 });
603 }
604
605 #[test]
606 fn test_strings_are_sequences() {
607 Python::with_gil(|py| {
608 let v = "London Calling";
609 assert!(v.to_object(py).downcast_bound::<PySequence>(py).is_ok());
610 });
611 }
612
613 #[test]
614 fn test_strings_cannot_be_extracted_to_vec() {
615 Python::with_gil(|py| {
616 let v = "London Calling";
617 let ob = v.to_object(py);
618
619 assert!(ob.extract::<Vec<String>>(py).is_err());
620 assert!(ob.extract::<Vec<char>>(py).is_err());
621 });
622 }
623
624 #[test]
625 fn test_seq_empty() {
626 Python::with_gil(|py| {
627 let v: Vec<i32> = vec![];
628 let ob = v.to_object(py);
629 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
630 assert_eq!(0, seq.len().unwrap());
631
632 let needle = 7i32.to_object(py);
633 assert!(!seq.contains(&needle).unwrap());
634 });
635 }
636
637 #[test]
638 fn test_seq_is_empty() {
639 Python::with_gil(|py| {
640 let list = vec![1].to_object(py);
641 let seq = list.downcast_bound::<PySequence>(py).unwrap();
642 assert!(!seq.is_empty().unwrap());
643 let vec: Vec<u32> = Vec::new();
644 let empty_list = vec.to_object(py);
645 let empty_seq = empty_list.downcast_bound::<PySequence>(py).unwrap();
646 assert!(empty_seq.is_empty().unwrap());
647 });
648 }
649
650 #[test]
651 fn test_seq_contains() {
652 Python::with_gil(|py| {
653 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
654 let ob = v.to_object(py);
655 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
656 assert_eq!(6, seq.len().unwrap());
657
658 let bad_needle = 7i32.to_object(py);
659 assert!(!seq.contains(&bad_needle).unwrap());
660
661 let good_needle = 8i32.to_object(py);
662 assert!(seq.contains(&good_needle).unwrap());
663
664 let type_coerced_needle = 8f32.to_object(py);
665 assert!(seq.contains(&type_coerced_needle).unwrap());
666 });
667 }
668
669 #[test]
670 fn test_seq_get_item() {
671 Python::with_gil(|py| {
672 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
673 let ob = v.to_object(py);
674 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
675 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
676 assert_eq!(1, seq.get_item(1).unwrap().extract::<i32>().unwrap());
677 assert_eq!(2, seq.get_item(2).unwrap().extract::<i32>().unwrap());
678 assert_eq!(3, seq.get_item(3).unwrap().extract::<i32>().unwrap());
679 assert_eq!(5, seq.get_item(4).unwrap().extract::<i32>().unwrap());
680 assert_eq!(8, seq.get_item(5).unwrap().extract::<i32>().unwrap());
681 assert!(seq.get_item(10).is_err());
682 });
683 }
684
685 #[test]
686 #[cfg(feature = "gil-refs")]
687 #[allow(deprecated)]
688 fn test_seq_index_trait() {
689 Python::with_gil(|py| {
690 let v: Vec<i32> = vec![1, 1, 2];
691 let ob = v.to_object(py);
692 let seq = ob.downcast::<PySequence>(py).unwrap();
693 assert_eq!(1, seq[0].extract::<i32>().unwrap());
694 assert_eq!(1, seq[1].extract::<i32>().unwrap());
695 assert_eq!(2, seq[2].extract::<i32>().unwrap());
696 });
697 }
698
699 #[test]
700 #[should_panic = "index 7 out of range for sequence"]
701 #[cfg(feature = "gil-refs")]
702 #[allow(deprecated)]
703 fn test_seq_index_trait_panic() {
704 Python::with_gil(|py| {
705 let v: Vec<i32> = vec![1, 1, 2];
706 let ob = v.to_object(py);
707 let seq = ob.downcast::<PySequence>(py).unwrap();
708 let _ = &seq[7];
709 });
710 }
711
712 #[test]
713 #[cfg(feature = "gil-refs")]
714 #[allow(deprecated)]
715 fn test_seq_index_trait_ranges() {
716 Python::with_gil(|py| {
717 let v: Vec<i32> = vec![1, 1, 2];
718 let ob = v.to_object(py);
719 let seq = ob.downcast::<PySequence>(py).unwrap();
720 assert_eq!(vec![1, 2], seq[1..3].extract::<Vec<i32>>().unwrap());
721 assert_eq!(Vec::<i32>::new(), seq[3..3].extract::<Vec<i32>>().unwrap());
722 assert_eq!(vec![1, 2], seq[1..].extract::<Vec<i32>>().unwrap());
723 assert_eq!(Vec::<i32>::new(), seq[3..].extract::<Vec<i32>>().unwrap());
724 assert_eq!(vec![1, 1, 2], seq[..].extract::<Vec<i32>>().unwrap());
725 assert_eq!(vec![1, 2], seq[1..=2].extract::<Vec<i32>>().unwrap());
726 assert_eq!(vec![1, 1], seq[..2].extract::<Vec<i32>>().unwrap());
727 assert_eq!(vec![1, 1], seq[..=1].extract::<Vec<i32>>().unwrap());
728 })
729 }
730
731 #[test]
732 #[should_panic = "range start index 5 out of range for sequence of length 3"]
733 #[cfg(feature = "gil-refs")]
734 #[allow(deprecated)]
735 fn test_seq_index_trait_range_panic_start() {
736 Python::with_gil(|py| {
737 let v: Vec<i32> = vec![1, 1, 2];
738 let ob = v.to_object(py);
739 let seq = ob.downcast::<PySequence>(py).unwrap();
740 seq[5..10].extract::<Vec<i32>>().unwrap();
741 })
742 }
743
744 #[test]
745 #[should_panic = "range end index 10 out of range for sequence of length 3"]
746 #[cfg(feature = "gil-refs")]
747 #[allow(deprecated)]
748 fn test_seq_index_trait_range_panic_end() {
749 Python::with_gil(|py| {
750 let v: Vec<i32> = vec![1, 1, 2];
751 let ob = v.to_object(py);
752 let seq = ob.downcast::<PySequence>(py).unwrap();
753 seq[1..10].extract::<Vec<i32>>().unwrap();
754 })
755 }
756
757 #[test]
758 #[should_panic = "slice index starts at 2 but ends at 1"]
759 #[cfg(feature = "gil-refs")]
760 #[allow(deprecated)]
761 fn test_seq_index_trait_range_panic_wrong_order() {
762 Python::with_gil(|py| {
763 let v: Vec<i32> = vec![1, 1, 2];
764 let ob = v.to_object(py);
765 let seq = ob.downcast::<PySequence>(py).unwrap();
766 #[allow(clippy::reversed_empty_ranges)]
767 seq[2..1].extract::<Vec<i32>>().unwrap();
768 })
769 }
770
771 #[test]
772 #[should_panic = "range start index 8 out of range for sequence of length 3"]
773 #[cfg(feature = "gil-refs")]
774 #[allow(deprecated)]
775 fn test_seq_index_trait_range_from_panic() {
776 Python::with_gil(|py| {
777 let v: Vec<i32> = vec![1, 1, 2];
778 let ob = v.to_object(py);
779 let seq = ob.downcast::<PySequence>(py).unwrap();
780 seq[8..].extract::<Vec<i32>>().unwrap();
781 })
782 }
783
784 #[test]
785 fn test_seq_del_item() {
786 Python::with_gil(|py| {
787 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
788 let ob = v.to_object(py);
789 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
790 assert!(seq.del_item(10).is_err());
791 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
792 assert!(seq.del_item(0).is_ok());
793 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
794 assert!(seq.del_item(0).is_ok());
795 assert_eq!(2, seq.get_item(0).unwrap().extract::<i32>().unwrap());
796 assert!(seq.del_item(0).is_ok());
797 assert_eq!(3, seq.get_item(0).unwrap().extract::<i32>().unwrap());
798 assert!(seq.del_item(0).is_ok());
799 assert_eq!(5, seq.get_item(0).unwrap().extract::<i32>().unwrap());
800 assert!(seq.del_item(0).is_ok());
801 assert_eq!(8, seq.get_item(0).unwrap().extract::<i32>().unwrap());
802 assert!(seq.del_item(0).is_ok());
803 assert_eq!(0, seq.len().unwrap());
804 assert!(seq.del_item(0).is_err());
805 });
806 }
807
808 #[test]
809 fn test_seq_set_item() {
810 Python::with_gil(|py| {
811 let v: Vec<i32> = vec![1, 2];
812 let ob = v.to_object(py);
813 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
814 assert_eq!(2, seq.get_item(1).unwrap().extract::<i32>().unwrap());
815 assert!(seq.set_item(1, 10).is_ok());
816 assert_eq!(10, seq.get_item(1).unwrap().extract::<i32>().unwrap());
817 });
818 }
819
820 #[test]
821 fn test_seq_set_item_refcnt() {
822 let obj = get_object();
823
824 Python::with_gil(|py| {
825 let v: Vec<i32> = vec![1, 2];
826 let ob = v.to_object(py);
827 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
828 assert!(seq.set_item(1, &obj).is_ok());
829 assert!(seq.get_item(1).unwrap().as_ptr() == obj.as_ptr());
830 });
831
832 Python::with_gil(move |py| {
833 assert_eq!(1, obj.get_refcnt(py));
834 });
835 }
836
837 #[test]
838 fn test_seq_get_slice() {
839 Python::with_gil(|py| {
840 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
841 let ob = v.to_object(py);
842 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
843 assert_eq!(
844 [1, 2, 3],
845 seq.get_slice(1, 4).unwrap().extract::<[i32; 3]>().unwrap()
846 );
847 assert_eq!(
848 [3, 5, 8],
849 seq.get_slice(3, 100)
850 .unwrap()
851 .extract::<[i32; 3]>()
852 .unwrap()
853 );
854 });
855 }
856
857 #[test]
858 fn test_set_slice() {
859 Python::with_gil(|py| {
860 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
861 let w: Vec<i32> = vec![7, 4];
862 let ob = v.to_object(py);
863 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
864 let ins = w.to_object(py);
865 seq.set_slice(1, 4, ins.bind(py)).unwrap();
866 assert_eq!([1, 7, 4, 5, 8], seq.extract::<[i32; 5]>().unwrap());
867 seq.set_slice(3, 100, &PyList::empty_bound(py)).unwrap();
868 assert_eq!([1, 7, 4], seq.extract::<[i32; 3]>().unwrap());
869 });
870 }
871
872 #[test]
873 fn test_del_slice() {
874 Python::with_gil(|py| {
875 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
876 let ob = v.to_object(py);
877 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
878 seq.del_slice(1, 4).unwrap();
879 assert_eq!([1, 5, 8], seq.extract::<[i32; 3]>().unwrap());
880 seq.del_slice(1, 100).unwrap();
881 assert_eq!([1], seq.extract::<[i32; 1]>().unwrap());
882 });
883 }
884
885 #[test]
886 fn test_seq_index() {
887 Python::with_gil(|py| {
888 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
889 let ob = v.to_object(py);
890 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
891 assert_eq!(0, seq.index(1i32).unwrap());
892 assert_eq!(2, seq.index(2i32).unwrap());
893 assert_eq!(3, seq.index(3i32).unwrap());
894 assert_eq!(4, seq.index(5i32).unwrap());
895 assert_eq!(5, seq.index(8i32).unwrap());
896 assert!(seq.index(42i32).is_err());
897 });
898 }
899
900 #[test]
901 #[cfg(not(any(PyPy, GraalPy)))]
902 fn test_seq_count() {
903 Python::with_gil(|py| {
904 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
905 let ob = v.to_object(py);
906 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
907 assert_eq!(2, seq.count(1i32).unwrap());
908 assert_eq!(1, seq.count(2i32).unwrap());
909 assert_eq!(1, seq.count(3i32).unwrap());
910 assert_eq!(1, seq.count(5i32).unwrap());
911 assert_eq!(1, seq.count(8i32).unwrap());
912 assert_eq!(0, seq.count(42i32).unwrap());
913 });
914 }
915
916 #[test]
917 fn test_seq_iter() {
918 Python::with_gil(|py| {
919 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
920 let ob = v.to_object(py);
921 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
922 let mut idx = 0;
923 for el in seq.iter().unwrap() {
924 assert_eq!(v[idx], el.unwrap().extract::<i32>().unwrap());
925 idx += 1;
926 }
927 assert_eq!(idx, v.len());
928 });
929 }
930
931 #[test]
932 fn test_seq_strings() {
933 Python::with_gil(|py| {
934 let v = vec!["It", "was", "the", "worst", "of", "times"];
935 let ob = v.to_object(py);
936 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
937
938 let bad_needle = "blurst".to_object(py);
939 assert!(!seq.contains(bad_needle).unwrap());
940
941 let good_needle = "worst".to_object(py);
942 assert!(seq.contains(good_needle).unwrap());
943 });
944 }
945
946 #[test]
947 fn test_seq_concat() {
948 Python::with_gil(|py| {
949 let v: Vec<i32> = vec![1, 2, 3];
950 let ob = v.to_object(py);
951 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
952 let concat_seq = seq.concat(seq).unwrap();
953 assert_eq!(6, concat_seq.len().unwrap());
954 let concat_v: Vec<i32> = vec![1, 2, 3, 1, 2, 3];
955 for (el, cc) in concat_seq.iter().unwrap().zip(concat_v) {
956 assert_eq!(cc, el.unwrap().extract::<i32>().unwrap());
957 }
958 });
959 }
960
961 #[test]
962 fn test_seq_concat_string() {
963 Python::with_gil(|py| {
964 let v = "string";
965 let ob = v.to_object(py);
966 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
967 let concat_seq = seq.concat(seq).unwrap();
968 assert_eq!(12, concat_seq.len().unwrap());
969 let concat_v = "stringstring".to_owned();
970 for (el, cc) in seq.iter().unwrap().zip(concat_v.chars()) {
971 assert_eq!(cc, el.unwrap().extract::<char>().unwrap());
972 }
973 });
974 }
975
976 #[test]
977 fn test_seq_repeat() {
978 Python::with_gil(|py| {
979 let v = vec!["foo", "bar"];
980 let ob = v.to_object(py);
981 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
982 let repeat_seq = seq.repeat(3).unwrap();
983 assert_eq!(6, repeat_seq.len().unwrap());
984 let repeated = ["foo", "bar", "foo", "bar", "foo", "bar"];
985 for (el, rpt) in repeat_seq.iter().unwrap().zip(repeated.iter()) {
986 assert_eq!(*rpt, el.unwrap().extract::<String>().unwrap());
987 }
988 });
989 }
990
991 #[test]
992 fn test_seq_inplace() {
993 Python::with_gil(|py| {
994 let v = vec!["foo", "bar"];
995 let ob = v.to_object(py);
996 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
997 let rep_seq = seq.in_place_repeat(3).unwrap();
998 assert_eq!(6, seq.len().unwrap());
999 assert!(seq.is(&rep_seq));
1000
1001 let conc_seq = seq.in_place_concat(seq).unwrap();
1002 assert_eq!(12, seq.len().unwrap());
1003 assert!(seq.is(&conc_seq));
1004 });
1005 }
1006
1007 #[test]
1008 fn test_list_coercion() {
1009 Python::with_gil(|py| {
1010 let v = vec!["foo", "bar"];
1011 let ob = v.to_object(py);
1012 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
1013 assert!(seq
1014 .to_list()
1015 .unwrap()
1016 .eq(PyList::new_bound(py, &v))
1017 .unwrap());
1018 });
1019 }
1020
1021 #[test]
1022 fn test_strings_coerce_to_lists() {
1023 Python::with_gil(|py| {
1024 let v = "foo";
1025 let ob = v.to_object(py);
1026 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
1027 assert!(seq
1028 .to_list()
1029 .unwrap()
1030 .eq(PyList::new_bound(py, ["f", "o", "o"]))
1031 .unwrap());
1032 });
1033 }
1034
1035 #[test]
1036 fn test_tuple_coercion() {
1037 Python::with_gil(|py| {
1038 let v = ("foo", "bar");
1039 let ob = v.to_object(py);
1040 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
1041 assert!(seq
1042 .to_tuple()
1043 .unwrap()
1044 .eq(PyTuple::new_bound(py, ["foo", "bar"]))
1045 .unwrap());
1046 });
1047 }
1048
1049 #[test]
1050 fn test_lists_coerce_to_tuples() {
1051 Python::with_gil(|py| {
1052 let v = vec!["foo", "bar"];
1053 let ob = v.to_object(py);
1054 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
1055 assert!(seq
1056 .to_tuple()
1057 .unwrap()
1058 .eq(PyTuple::new_bound(py, &v))
1059 .unwrap());
1060 });
1061 }
1062
1063 #[test]
1064 fn test_extract_tuple_to_vec() {
1065 Python::with_gil(|py| {
1066 let v: Vec<i32> = py
1067 .eval_bound("(1, 2)", None, None)
1068 .unwrap()
1069 .extract()
1070 .unwrap();
1071 assert!(v == [1, 2]);
1072 });
1073 }
1074
1075 #[test]
1076 fn test_extract_range_to_vec() {
1077 Python::with_gil(|py| {
1078 let v: Vec<i32> = py
1079 .eval_bound("range(1, 5)", None, None)
1080 .unwrap()
1081 .extract()
1082 .unwrap();
1083 assert!(v == [1, 2, 3, 4]);
1084 });
1085 }
1086
1087 #[test]
1088 fn test_extract_bytearray_to_vec() {
1089 Python::with_gil(|py| {
1090 let v: Vec<u8> = py
1091 .eval_bound("bytearray(b'abc')", None, None)
1092 .unwrap()
1093 .extract()
1094 .unwrap();
1095 assert!(v == b"abc");
1096 });
1097 }
1098
1099 #[test]
1100 fn test_seq_downcast_unchecked() {
1101 Python::with_gil(|py| {
1102 let v = vec!["foo", "bar"];
1103 let ob = v.to_object(py);
1104 let seq = ob.downcast_bound::<PySequence>(py).unwrap();
1105 let type_ptr = seq.as_ref();
1106 let seq_from = unsafe { type_ptr.downcast_unchecked::<PySequence>() };
1107 assert!(seq_from.to_list().is_ok());
1108 });
1109 }
1110
1111 #[test]
1112 #[cfg(feature = "gil-refs")]
1113 #[allow(deprecated)]
1114 fn test_seq_try_from() {
1115 use crate::PyTryFrom;
1116 Python::with_gil(|py| {
1117 let list = PyList::empty(py);
1118 let _ = <PySequence as PyTryFrom>::try_from(list).unwrap();
1119 let _ = PySequence::try_from_exact(list).unwrap();
1120 });
1121 }
1122}