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