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};
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 .downcast_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 .downcast_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 .downcast_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 .downcast_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 .downcast_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 .downcast_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 .downcast_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.downcast_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: GILOnceCell<Py<PyType>> = GILOnceCell::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, PyObject, Python};
402 use std::ptr;
403
404 fn get_object() -> PyObject {
405 Python::with_gil(|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::with_gil(|py| {
416 let v = 42i32;
417 assert!(v
418 .into_pyobject(py)
419 .unwrap()
420 .downcast::<PySequence>()
421 .is_err());
422 });
423 }
424
425 #[test]
426 fn test_strings_are_sequences() {
427 Python::with_gil(|py| {
428 let v = "London Calling";
429 assert!(v
430 .into_pyobject(py)
431 .unwrap()
432 .downcast::<PySequence>()
433 .is_ok());
434 });
435 }
436
437 #[test]
438 fn test_strings_cannot_be_extracted_to_vec() {
439 Python::with_gil(|py| {
440 let v = "London Calling";
441 let ob = v.into_pyobject(py).unwrap();
442
443 assert!(ob.extract::<Vec<String>>().is_err());
444 assert!(ob.extract::<Vec<char>>().is_err());
445 });
446 }
447
448 #[test]
449 fn test_seq_empty() {
450 Python::with_gil(|py| {
451 let v: Vec<i32> = vec![];
452 let ob = v.into_pyobject(py).unwrap();
453 let seq = ob.downcast::<PySequence>().unwrap();
454 assert_eq!(0, seq.len().unwrap());
455
456 let needle = 7i32.into_pyobject(py).unwrap();
457 assert!(!seq.contains(&needle).unwrap());
458 });
459 }
460
461 #[test]
462 fn test_seq_is_empty() {
463 Python::with_gil(|py| {
464 let list = vec![1].into_pyobject(py).unwrap();
465 let seq = list.downcast::<PySequence>().unwrap();
466 assert!(!seq.is_empty().unwrap());
467 let vec: Vec<u32> = Vec::new();
468 let empty_list = vec.into_pyobject(py).unwrap();
469 let empty_seq = empty_list.downcast::<PySequence>().unwrap();
470 assert!(empty_seq.is_empty().unwrap());
471 });
472 }
473
474 #[test]
475 fn test_seq_contains() {
476 Python::with_gil(|py| {
477 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
478 let ob = v.into_pyobject(py).unwrap();
479 let seq = ob.downcast::<PySequence>().unwrap();
480 assert_eq!(6, seq.len().unwrap());
481
482 let bad_needle = 7i32.into_pyobject(py).unwrap();
483 assert!(!seq.contains(&bad_needle).unwrap());
484
485 let good_needle = 8i32.into_pyobject(py).unwrap();
486 assert!(seq.contains(&good_needle).unwrap());
487
488 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
489 assert!(seq.contains(&type_coerced_needle).unwrap());
490 });
491 }
492
493 #[test]
494 fn test_seq_get_item() {
495 Python::with_gil(|py| {
496 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
497 let ob = v.into_pyobject(py).unwrap();
498 let seq = ob.downcast::<PySequence>().unwrap();
499 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
500 assert_eq!(1, seq.get_item(1).unwrap().extract::<i32>().unwrap());
501 assert_eq!(2, seq.get_item(2).unwrap().extract::<i32>().unwrap());
502 assert_eq!(3, seq.get_item(3).unwrap().extract::<i32>().unwrap());
503 assert_eq!(5, seq.get_item(4).unwrap().extract::<i32>().unwrap());
504 assert_eq!(8, seq.get_item(5).unwrap().extract::<i32>().unwrap());
505 assert!(seq.get_item(10).is_err());
506 });
507 }
508
509 #[test]
510 fn test_seq_del_item() {
511 Python::with_gil(|py| {
512 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
513 let ob = v.into_pyobject(py).unwrap();
514 let seq = ob.downcast::<PySequence>().unwrap();
515 assert!(seq.del_item(10).is_err());
516 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
517 assert!(seq.del_item(0).is_ok());
518 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
519 assert!(seq.del_item(0).is_ok());
520 assert_eq!(2, seq.get_item(0).unwrap().extract::<i32>().unwrap());
521 assert!(seq.del_item(0).is_ok());
522 assert_eq!(3, seq.get_item(0).unwrap().extract::<i32>().unwrap());
523 assert!(seq.del_item(0).is_ok());
524 assert_eq!(5, seq.get_item(0).unwrap().extract::<i32>().unwrap());
525 assert!(seq.del_item(0).is_ok());
526 assert_eq!(8, seq.get_item(0).unwrap().extract::<i32>().unwrap());
527 assert!(seq.del_item(0).is_ok());
528 assert_eq!(0, seq.len().unwrap());
529 assert!(seq.del_item(0).is_err());
530 });
531 }
532
533 #[test]
534 fn test_seq_set_item() {
535 Python::with_gil(|py| {
536 let v: Vec<i32> = vec![1, 2];
537 let ob = v.into_pyobject(py).unwrap();
538 let seq = ob.downcast::<PySequence>().unwrap();
539 assert_eq!(2, seq.get_item(1).unwrap().extract::<i32>().unwrap());
540 assert!(seq.set_item(1, 10).is_ok());
541 assert_eq!(10, seq.get_item(1).unwrap().extract::<i32>().unwrap());
542 });
543 }
544
545 #[test]
546 fn test_seq_set_item_refcnt() {
547 let obj = get_object();
548
549 Python::with_gil(|py| {
550 let v: Vec<i32> = vec![1, 2];
551 let ob = v.into_pyobject(py).unwrap();
552 let seq = ob.downcast::<PySequence>().unwrap();
553 assert!(seq.set_item(1, &obj).is_ok());
554 assert!(ptr::eq(seq.get_item(1).unwrap().as_ptr(), obj.as_ptr()));
555 });
556
557 Python::with_gil(move |py| {
558 assert_eq!(1, obj.get_refcnt(py));
559 });
560 }
561
562 #[test]
563 fn test_seq_get_slice() {
564 Python::with_gil(|py| {
565 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
566 let ob = v.into_pyobject(py).unwrap();
567 let seq = ob.downcast::<PySequence>().unwrap();
568 assert_eq!(
569 [1, 2, 3],
570 seq.get_slice(1, 4).unwrap().extract::<[i32; 3]>().unwrap()
571 );
572 assert_eq!(
573 [3, 5, 8],
574 seq.get_slice(3, 100)
575 .unwrap()
576 .extract::<[i32; 3]>()
577 .unwrap()
578 );
579 });
580 }
581
582 #[test]
583 fn test_set_slice() {
584 Python::with_gil(|py| {
585 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
586 let w: Vec<i32> = vec![7, 4];
587 let ob = v.into_pyobject(py).unwrap();
588 let seq = ob.downcast::<PySequence>().unwrap();
589 let ins = w.into_pyobject(py).unwrap();
590 seq.set_slice(1, 4, &ins).unwrap();
591 assert_eq!([1, 7, 4, 5, 8], seq.extract::<[i32; 5]>().unwrap());
592 seq.set_slice(3, 100, &PyList::empty(py)).unwrap();
593 assert_eq!([1, 7, 4], seq.extract::<[i32; 3]>().unwrap());
594 });
595 }
596
597 #[test]
598 fn test_del_slice() {
599 Python::with_gil(|py| {
600 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
601 let ob = v.into_pyobject(py).unwrap();
602 let seq = ob.downcast::<PySequence>().unwrap();
603 seq.del_slice(1, 4).unwrap();
604 assert_eq!([1, 5, 8], seq.extract::<[i32; 3]>().unwrap());
605 seq.del_slice(1, 100).unwrap();
606 assert_eq!([1], seq.extract::<[i32; 1]>().unwrap());
607 });
608 }
609
610 #[test]
611 fn test_seq_index() {
612 Python::with_gil(|py| {
613 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
614 let ob = v.into_pyobject(py).unwrap();
615 let seq = ob.downcast::<PySequence>().unwrap();
616 assert_eq!(0, seq.index(1i32).unwrap());
617 assert_eq!(2, seq.index(2i32).unwrap());
618 assert_eq!(3, seq.index(3i32).unwrap());
619 assert_eq!(4, seq.index(5i32).unwrap());
620 assert_eq!(5, seq.index(8i32).unwrap());
621 assert!(seq.index(42i32).is_err());
622 });
623 }
624
625 #[test]
626 #[cfg(not(any(PyPy, GraalPy)))]
627 fn test_seq_count() {
628 Python::with_gil(|py| {
629 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
630 let ob = v.into_pyobject(py).unwrap();
631 let seq = ob.downcast::<PySequence>().unwrap();
632 assert_eq!(2, seq.count(1i32).unwrap());
633 assert_eq!(1, seq.count(2i32).unwrap());
634 assert_eq!(1, seq.count(3i32).unwrap());
635 assert_eq!(1, seq.count(5i32).unwrap());
636 assert_eq!(1, seq.count(8i32).unwrap());
637 assert_eq!(0, seq.count(42i32).unwrap());
638 });
639 }
640
641 #[test]
642 fn test_seq_iter() {
643 Python::with_gil(|py| {
644 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
645 let ob = (&v).into_pyobject(py).unwrap();
646 let seq = ob.downcast::<PySequence>().unwrap();
647 let mut idx = 0;
648 for el in seq.try_iter().unwrap() {
649 assert_eq!(v[idx], el.unwrap().extract::<i32>().unwrap());
650 idx += 1;
651 }
652 assert_eq!(idx, v.len());
653 });
654 }
655
656 #[test]
657 fn test_seq_strings() {
658 Python::with_gil(|py| {
659 let v = vec!["It", "was", "the", "worst", "of", "times"];
660 let ob = v.into_pyobject(py).unwrap();
661 let seq = ob.downcast::<PySequence>().unwrap();
662
663 let bad_needle = "blurst".into_pyobject(py).unwrap();
664 assert!(!seq.contains(bad_needle).unwrap());
665
666 let good_needle = "worst".into_pyobject(py).unwrap();
667 assert!(seq.contains(good_needle).unwrap());
668 });
669 }
670
671 #[test]
672 fn test_seq_concat() {
673 Python::with_gil(|py| {
674 let v: Vec<i32> = vec![1, 2, 3];
675 let ob = v.into_pyobject(py).unwrap();
676 let seq = ob.downcast::<PySequence>().unwrap();
677 let concat_seq = seq.concat(seq).unwrap();
678 assert_eq!(6, concat_seq.len().unwrap());
679 let concat_v: Vec<i32> = vec![1, 2, 3, 1, 2, 3];
680 for (el, cc) in concat_seq.try_iter().unwrap().zip(concat_v) {
681 assert_eq!(cc, el.unwrap().extract::<i32>().unwrap());
682 }
683 });
684 }
685
686 #[test]
687 fn test_seq_concat_string() {
688 Python::with_gil(|py| {
689 let v = "string";
690 let ob = v.into_pyobject(py).unwrap();
691 let seq = ob.downcast::<PySequence>().unwrap();
692 let concat_seq = seq.concat(seq).unwrap();
693 assert_eq!(12, concat_seq.len().unwrap());
694 let concat_v = "stringstring".to_owned();
695 for (el, cc) in seq.try_iter().unwrap().zip(concat_v.chars()) {
696 assert_eq!(cc, el.unwrap().extract::<char>().unwrap());
697 }
698 });
699 }
700
701 #[test]
702 fn test_seq_repeat() {
703 Python::with_gil(|py| {
704 let v = vec!["foo", "bar"];
705 let ob = v.into_pyobject(py).unwrap();
706 let seq = ob.downcast::<PySequence>().unwrap();
707 let repeat_seq = seq.repeat(3).unwrap();
708 assert_eq!(6, repeat_seq.len().unwrap());
709 let repeated = ["foo", "bar", "foo", "bar", "foo", "bar"];
710 for (el, rpt) in repeat_seq.try_iter().unwrap().zip(repeated.iter()) {
711 assert_eq!(*rpt, el.unwrap().extract::<String>().unwrap());
712 }
713 });
714 }
715
716 #[test]
717 fn test_seq_inplace() {
718 Python::with_gil(|py| {
719 let v = vec!["foo", "bar"];
720 let ob = v.into_pyobject(py).unwrap();
721 let seq = ob.downcast::<PySequence>().unwrap();
722 let rep_seq = seq.in_place_repeat(3).unwrap();
723 assert_eq!(6, seq.len().unwrap());
724 assert!(seq.is(&rep_seq));
725
726 let conc_seq = seq.in_place_concat(seq).unwrap();
727 assert_eq!(12, seq.len().unwrap());
728 assert!(seq.is(&conc_seq));
729 });
730 }
731
732 #[test]
733 fn test_list_coercion() {
734 Python::with_gil(|py| {
735 let v = vec!["foo", "bar"];
736 let ob = (&v).into_pyobject(py).unwrap();
737 let seq = ob.downcast::<PySequence>().unwrap();
738 assert!(seq
739 .to_list()
740 .unwrap()
741 .eq(PyList::new(py, &v).unwrap())
742 .unwrap());
743 });
744 }
745
746 #[test]
747 fn test_strings_coerce_to_lists() {
748 Python::with_gil(|py| {
749 let v = "foo";
750 let ob = v.into_pyobject(py).unwrap();
751 let seq = ob.downcast::<PySequence>().unwrap();
752 assert!(seq
753 .to_list()
754 .unwrap()
755 .eq(PyList::new(py, ["f", "o", "o"]).unwrap())
756 .unwrap());
757 });
758 }
759
760 #[test]
761 fn test_tuple_coercion() {
762 Python::with_gil(|py| {
763 let v = ("foo", "bar");
764 let ob = v.into_pyobject(py).unwrap();
765 let seq = ob.downcast::<PySequence>().unwrap();
766 assert!(seq
767 .to_tuple()
768 .unwrap()
769 .eq(PyTuple::new(py, ["foo", "bar"]).unwrap())
770 .unwrap());
771 });
772 }
773
774 #[test]
775 fn test_lists_coerce_to_tuples() {
776 Python::with_gil(|py| {
777 let v = vec!["foo", "bar"];
778 let ob = (&v).into_pyobject(py).unwrap();
779 let seq = ob.downcast::<PySequence>().unwrap();
780 assert!(seq
781 .to_tuple()
782 .unwrap()
783 .eq(PyTuple::new(py, &v).unwrap())
784 .unwrap());
785 });
786 }
787
788 #[test]
789 fn test_extract_tuple_to_vec() {
790 Python::with_gil(|py| {
791 let v: Vec<i32> = py
792 .eval(ffi::c_str!("(1, 2)"), None, None)
793 .unwrap()
794 .extract()
795 .unwrap();
796 assert!(v == [1, 2]);
797 });
798 }
799
800 #[test]
801 fn test_extract_range_to_vec() {
802 Python::with_gil(|py| {
803 let v: Vec<i32> = py
804 .eval(ffi::c_str!("range(1, 5)"), None, None)
805 .unwrap()
806 .extract()
807 .unwrap();
808 assert!(v == [1, 2, 3, 4]);
809 });
810 }
811
812 #[test]
813 fn test_extract_bytearray_to_vec() {
814 Python::with_gil(|py| {
815 let v: Vec<u8> = py
816 .eval(ffi::c_str!("bytearray(b'abc')"), None, None)
817 .unwrap()
818 .extract()
819 .unwrap();
820 assert!(v == b"abc");
821 });
822 }
823
824 #[test]
825 fn test_seq_downcast_unchecked() {
826 Python::with_gil(|py| {
827 let v = vec!["foo", "bar"];
828 let ob = v.into_pyobject(py).unwrap();
829 let seq = ob.downcast::<PySequence>().unwrap();
830 let type_ptr = seq.as_any();
831 let seq_from = unsafe { type_ptr.downcast_unchecked::<PySequence>() };
832 assert!(seq_from.to_list().is_ok());
833 });
834 }
835}