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