1use crate::err::{self, PyDowncastError, PyErr, PyResult};
2use crate::exceptions::PyTypeError;
3#[cfg(feature = "experimental-inspect")]
4use crate::inspect::types::TypeInfo;
5use crate::internal_tricks::get_ssize_index;
6use crate::sync::GILOnceCell;
7use crate::type_object::PyTypeInfo;
8use crate::types::{PyAny, PyList, PyString, PyTuple, PyType};
9use crate::{ffi, PyNativeType, PyObject, ToPyObject};
10use crate::{FromPyObject, PyTryFrom};
11use crate::{Py, Python};
12
13/// Represents a reference to a Python object supporting the sequence protocol.
14#[repr(transparent)]
15pub struct PySequence(PyAny);
16pyobject_native_type_named!(PySequence);
17pyobject_native_type_extract!(PySequence);
18
19impl PySequence {
20 /// Returns the number of objects in sequence.
21 ///
22 /// This is equivalent to the Python expression `len(self)`.
23 #[inline]
24 pub fn len(&self) -> PyResult<usize> {
25 let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
26 crate::err::error_on_minusone(self.py(), v)?;
27 Ok(v as usize)
28 }
29
30 /// Returns whether the sequence is empty.
31 #[inline]
32 pub fn is_empty(&self) -> PyResult<bool> {
33 self.len().map(|l| l == 0)
34 }
35
36 /// Returns the concatenation of `self` and `other`.
37 ///
38 /// This is equivalent to the Python expression `self + other`.
39 #[inline]
40 pub fn concat(&self, other: &PySequence) -> PyResult<&PySequence> {
41 unsafe {
42 self.py()
43 .from_owned_ptr_or_err(ffi::PySequence_Concat(self.as_ptr(), other.as_ptr()))
44 }
45 }
46
47 /// Returns the result of repeating a sequence object `count` times.
48 ///
49 /// This is equivalent to the Python expression `self * count`.
50 #[inline]
51 pub fn repeat(&self, count: usize) -> PyResult<&PySequence> {
52 unsafe {
53 self.py().from_owned_ptr_or_err(ffi::PySequence_Repeat(
54 self.as_ptr(),
55 get_ssize_index(count),
56 ))
57 }
58 }
59
60 /// Concatenates `self` and `other`, in place if possible.
61 ///
62 /// This is equivalent to the Python expression `self.__iadd__(other)`.
63 ///
64 /// The Python statement `self += other` is syntactic sugar for `self =
65 /// self.__iadd__(other)`. `__iadd__` should modify and return `self` if
66 /// possible, but create and return a new object if not.
67 #[inline]
68 pub fn in_place_concat(&self, other: &PySequence) -> PyResult<&PySequence> {
69 unsafe {
70 self.py()
71 .from_owned_ptr_or_err(ffi::PySequence_InPlaceConcat(self.as_ptr(), other.as_ptr()))
72 }
73 }
74
75 /// Repeats the sequence object `count` times and updates `self`, if possible.
76 ///
77 /// This is equivalent to the Python expression `self.__imul__(other)`.
78 ///
79 /// The Python statement `self *= other` is syntactic sugar for `self =
80 /// self.__imul__(other)`. `__imul__` should modify and return `self` if
81 /// possible, but create and return a new object if not.
82 #[inline]
83 pub fn in_place_repeat(&self, count: usize) -> PyResult<&PySequence> {
84 unsafe {
85 self.py()
86 .from_owned_ptr_or_err(ffi::PySequence_InPlaceRepeat(
87 self.as_ptr(),
88 get_ssize_index(count),
89 ))
90 }
91 }
92
93 /// Returns the `index`th element of the Sequence.
94 ///
95 /// This is equivalent to the Python expression `self[index]` without support of negative indices.
96 #[inline]
97 pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
98 unsafe {
99 self.py().from_owned_ptr_or_err(ffi::PySequence_GetItem(
100 self.as_ptr(),
101 get_ssize_index(index),
102 ))
103 }
104 }
105
106 /// Returns the slice of sequence object between `begin` and `end`.
107 ///
108 /// This is equivalent to the Python expression `self[begin:end]`.
109 #[inline]
110 pub fn get_slice(&self, begin: usize, end: usize) -> PyResult<&PySequence> {
111 unsafe {
112 self.py().from_owned_ptr_or_err(ffi::PySequence_GetSlice(
113 self.as_ptr(),
114 get_ssize_index(begin),
115 get_ssize_index(end),
116 ))
117 }
118 }
119
120 /// Assigns object `item` to the `i`th element of self.
121 ///
122 /// This is equivalent to the Python statement `self[i] = v`.
123 #[inline]
124 pub fn set_item<I>(&self, i: usize, item: I) -> PyResult<()>
125 where
126 I: ToPyObject,
127 {
128 fn inner(seq: &PySequence, i: usize, item: PyObject) -> PyResult<()> {
129 err::error_on_minusone(seq.py(), unsafe {
130 ffi::PySequence_SetItem(seq.as_ptr(), get_ssize_index(i), item.as_ptr())
131 })
132 }
133
134 inner(self, i, item.to_object(self.py()))
135 }
136
137 /// Deletes the `i`th element of self.
138 ///
139 /// This is equivalent to the Python statement `del self[i]`.
140 #[inline]
141 pub fn del_item(&self, i: usize) -> PyResult<()> {
142 err::error_on_minusone(self.py(), unsafe {
143 ffi::PySequence_DelItem(self.as_ptr(), get_ssize_index(i))
144 })
145 }
146
147 /// Assigns the sequence `v` to the slice of `self` from `i1` to `i2`.
148 ///
149 /// This is equivalent to the Python statement `self[i1:i2] = v`.
150 #[inline]
151 pub fn set_slice(&self, i1: usize, i2: usize, v: &PyAny) -> PyResult<()> {
152 err::error_on_minusone(self.py(), unsafe {
153 ffi::PySequence_SetSlice(
154 self.as_ptr(),
155 get_ssize_index(i1),
156 get_ssize_index(i2),
157 v.as_ptr(),
158 )
159 })
160 }
161
162 /// Deletes the slice from `i1` to `i2` from `self`.
163 ///
164 /// This is equivalent to the Python statement `del self[i1:i2]`.
165 #[inline]
166 pub fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> {
167 err::error_on_minusone(self.py(), unsafe {
168 ffi::PySequence_DelSlice(self.as_ptr(), get_ssize_index(i1), get_ssize_index(i2))
169 })
170 }
171
172 /// Returns the number of occurrences of `value` in self, that is, return the
173 /// number of keys for which `self[key] == value`.
174 #[inline]
175 #[cfg(not(PyPy))]
176 pub fn count<V>(&self, value: V) -> PyResult<usize>
177 where
178 V: ToPyObject,
179 {
180 fn inner(seq: &PySequence, value: PyObject) -> PyResult<usize> {
181 let r = unsafe { ffi::PySequence_Count(seq.as_ptr(), value.as_ptr()) };
182 crate::err::error_on_minusone(seq.py(), r)?;
183 Ok(r as usize)
184 }
185
186 inner(self, value.to_object(self.py()))
187 }
188
189 /// Determines if self contains `value`.
190 ///
191 /// This is equivalent to the Python expression `value in self`.
192 #[inline]
193 pub fn contains<V>(&self, value: V) -> PyResult<bool>
194 where
195 V: ToPyObject,
196 {
197 fn inner(seq: &PySequence, value: PyObject) -> PyResult<bool> {
198 let r = unsafe { ffi::PySequence_Contains(seq.as_ptr(), value.as_ptr()) };
199 match r {
200 0 => Ok(false),
201 1 => Ok(true),
202 _ => Err(PyErr::fetch(seq.py())),
203 }
204 }
205
206 inner(self, value.to_object(self.py()))
207 }
208
209 /// Returns the first index `i` for which `self[i] == value`.
210 ///
211 /// This is equivalent to the Python expression `self.index(value)`.
212 #[inline]
213 pub fn index<V>(&self, value: V) -> PyResult<usize>
214 where
215 V: ToPyObject,
216 {
217 fn inner(seq: &PySequence, value: PyObject) -> PyResult<usize> {
218 let r = unsafe { ffi::PySequence_Index(seq.as_ptr(), value.as_ptr()) };
219 crate::err::error_on_minusone(seq.py(), r)?;
220 Ok(r as usize)
221 }
222
223 inner(self, value.to_object(self.py()))
224 }
225
226 /// Returns a fresh list based on the Sequence.
227 #[inline]
228 pub fn to_list(&self) -> PyResult<&PyList> {
229 unsafe {
230 self.py()
231 .from_owned_ptr_or_err(ffi::PySequence_List(self.as_ptr()))
232 }
233 }
234
235 /// Returns a fresh list based on the Sequence.
236 #[inline]
237 #[deprecated(since = "0.19.0", note = "renamed to .to_list()")]
238 pub fn list(&self) -> PyResult<&PyList> {
239 self.to_list()
240 }
241
242 /// Returns a fresh tuple based on the Sequence.
243 #[inline]
244 pub fn to_tuple(&self) -> PyResult<&PyTuple> {
245 unsafe {
246 self.py()
247 .from_owned_ptr_or_err(ffi::PySequence_Tuple(self.as_ptr()))
248 }
249 }
250
251 /// Returns a fresh tuple based on the Sequence.
252 #[inline]
253 #[deprecated(since = "0.19.0", note = "renamed to .to_tuple()")]
254 pub fn tuple(&self) -> PyResult<&PyTuple> {
255 self.to_tuple()
256 }
257
258 /// Register a pyclass as a subclass of `collections.abc.Sequence` (from the Python standard
259 /// library). This is equvalent to `collections.abc.Sequence.register(T)` in Python.
260 /// This registration is required for a pyclass to be downcastable from `PyAny` to `PySequence`.
261 pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
262 let ty = T::type_object(py);
263 get_sequence_abc(py)?.call_method1("register", (ty,))?;
264 Ok(())
265 }
266}
267
268#[inline]
269fn sequence_len(seq: &PySequence) -> usize {
270 seq.len().expect(msg:"failed to get sequence length")
271}
272
273#[inline]
274fn sequence_slice(seq: &PySequence, start: usize, end: usize) -> &PySequence {
275 seq.get_slice(start, end)
276 .expect(msg:"sequence slice operation failed")
277}
278
279index_impls!(PySequence, "sequence", sequence_len, sequence_slice);
280
281impl<'a, T> FromPyObject<'a> for Vec<T>
282where
283 T: FromPyObject<'a>,
284{
285 fn extract(obj: &'a PyAny) -> PyResult<Self> {
286 if obj.is_instance_of::<PyString>() {
287 return Err(PyTypeError::new_err(args:"Can't extract `str` to `Vec`"));
288 }
289 extract_sequence(obj)
290 }
291
292 #[cfg(feature = "experimental-inspect")]
293 fn type_input() -> TypeInfo {
294 TypeInfo::sequence_of(T::type_input())
295 }
296}
297
298fn extract_sequence<'s, T>(obj: &'s PyAny) -> PyResult<Vec<T>>
299where
300 T: FromPyObject<'s>,
301{
302 // Types that pass `PySequence_Check` usually implement enough of the sequence protocol
303 // to support this function and if not, we will only fail extraction safely.
304 let seq: &PySequence = unsafe {
305 if ffi::PySequence_Check(obj.as_ptr()) != 0 {
306 obj.downcast_unchecked()
307 } else {
308 return Err(PyDowncastError::new(from:obj, to:"Sequence").into());
309 }
310 };
311
312 let mut v: Vec = Vec::with_capacity(seq.len().unwrap_or(default:0));
313 for item: Result<&PyAny, PyErr> in seq.iter()? {
314 v.push(item?.extract::<T>()?);
315 }
316 Ok(v)
317}
318
319static SEQUENCE_ABC: GILOnceCell<Py<PyType>> = GILOnceCell::new();
320
321fn get_sequence_abc(py: Python<'_>) -> PyResult<&PyType> {
322 SEQUENCE_ABC
323 .get_or_try_init(py, || {
324 py.import("collections.abc")?.getattr("Sequence")?.extract()
325 })
326 .map(|ty: &Py| ty.as_ref(py))
327}
328
329impl<'v> PyTryFrom<'v> for PySequence {
330 /// Downcasting to `PySequence` requires the concrete class to be a subclass (or registered
331 /// subclass) of `collections.abc.Sequence` (from the Python standard library) - i.e.
332 /// `isinstance(<class>, collections.abc.Sequence) == True`.
333 fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
334 let value = value.into();
335
336 // Using `is_instance` for `collections.abc.Sequence` is slow, so provide
337 // optimized cases for list and tuples as common well-known sequences
338 if PyList::is_type_of(value)
339 || PyTuple::is_type_of(value)
340 || get_sequence_abc(value.py())
341 .and_then(|abc| value.is_instance(abc))
342 // TODO: surface errors in this chain to the user
343 .unwrap_or(false)
344 {
345 unsafe { return Ok(value.downcast_unchecked::<PySequence>()) }
346 }
347
348 Err(PyDowncastError::new(value, "Sequence"))
349 }
350
351 fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
352 value.into().downcast()
353 }
354
355 #[inline]
356 unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PySequence {
357 let ptr = value.into() as *const _ as *const PySequence;
358 &*ptr
359 }
360}
361
362impl Py<PySequence> {
363 /// Borrows a GIL-bound reference to the PySequence. By binding to the GIL lifetime, this
364 /// allows the GIL-bound reference to not require `Python` for any of its methods.
365 ///
366 /// ```
367 /// # use pyo3::prelude::*;
368 /// # use pyo3::types::{PyList, PySequence};
369 /// # Python::with_gil(|py| {
370 /// let seq: Py<PySequence> = PyList::empty(py).as_sequence().into();
371 /// let seq: &PySequence = seq.as_ref(py);
372 /// assert_eq!(seq.len().unwrap(), 0);
373 /// # });
374 /// ```
375 pub fn as_ref<'py>(&'py self, _py: Python<'py>) -> &'py PySequence {
376 let any = self.as_ptr() as *const PyAny;
377 unsafe { PyNativeType::unchecked_downcast(&*any) }
378 }
379
380 /// Similar to [`as_ref`](#method.as_ref), and also consumes this `Py` and registers the
381 /// Python object reference in PyO3's object storage. The reference count for the Python
382 /// object will not be decreased until the GIL lifetime ends.
383 pub fn into_ref(self, py: Python<'_>) -> &PySequence {
384 unsafe { py.from_owned_ptr(self.into_ptr()) }
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use crate::types::{PyList, PySequence, PyTuple};
391 use crate::{Py, PyObject, Python, ToPyObject};
392
393 fn get_object() -> PyObject {
394 // Convenience function for getting a single unique object
395 Python::with_gil(|py| {
396 let obj = py.eval("object()", None, None).unwrap();
397
398 obj.to_object(py)
399 })
400 }
401
402 #[test]
403 fn test_numbers_are_not_sequences() {
404 Python::with_gil(|py| {
405 let v = 42i32;
406 assert!(v.to_object(py).downcast::<PySequence>(py).is_err());
407 });
408 }
409
410 #[test]
411 fn test_strings_are_sequences() {
412 Python::with_gil(|py| {
413 let v = "London Calling";
414 assert!(v.to_object(py).downcast::<PySequence>(py).is_ok());
415 });
416 }
417
418 #[test]
419 fn test_strings_cannot_be_extracted_to_vec() {
420 Python::with_gil(|py| {
421 let v = "London Calling";
422 let ob = v.to_object(py);
423
424 assert!(ob.extract::<Vec<&str>>(py).is_err());
425 assert!(ob.extract::<Vec<String>>(py).is_err());
426 assert!(ob.extract::<Vec<char>>(py).is_err());
427 });
428 }
429
430 #[test]
431 fn test_seq_empty() {
432 Python::with_gil(|py| {
433 let v: Vec<i32> = vec![];
434 let ob = v.to_object(py);
435 let seq = ob.downcast::<PySequence>(py).unwrap();
436 assert_eq!(0, seq.len().unwrap());
437
438 let needle = 7i32.to_object(py);
439 assert!(!seq.contains(&needle).unwrap());
440 });
441 }
442
443 #[test]
444 fn test_seq_is_empty() {
445 Python::with_gil(|py| {
446 let list = vec![1].to_object(py);
447 let seq = list.downcast::<PySequence>(py).unwrap();
448 assert!(!seq.is_empty().unwrap());
449 let vec: Vec<u32> = Vec::new();
450 let empty_list = vec.to_object(py);
451 let empty_seq = empty_list.downcast::<PySequence>(py).unwrap();
452 assert!(empty_seq.is_empty().unwrap());
453 });
454 }
455
456 #[test]
457 fn test_seq_contains() {
458 Python::with_gil(|py| {
459 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
460 let ob = v.to_object(py);
461 let seq = ob.downcast::<PySequence>(py).unwrap();
462 assert_eq!(6, seq.len().unwrap());
463
464 let bad_needle = 7i32.to_object(py);
465 assert!(!seq.contains(&bad_needle).unwrap());
466
467 let good_needle = 8i32.to_object(py);
468 assert!(seq.contains(&good_needle).unwrap());
469
470 let type_coerced_needle = 8f32.to_object(py);
471 assert!(seq.contains(&type_coerced_needle).unwrap());
472 });
473 }
474
475 #[test]
476 fn test_seq_get_item() {
477 Python::with_gil(|py| {
478 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
479 let ob = v.to_object(py);
480 let seq = ob.downcast::<PySequence>(py).unwrap();
481 assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
482 assert_eq!(1, seq.get_item(1).unwrap().extract::<i32>().unwrap());
483 assert_eq!(2, seq.get_item(2).unwrap().extract::<i32>().unwrap());
484 assert_eq!(3, seq.get_item(3).unwrap().extract::<i32>().unwrap());
485 assert_eq!(5, seq.get_item(4).unwrap().extract::<i32>().unwrap());
486 assert_eq!(8, seq.get_item(5).unwrap().extract::<i32>().unwrap());
487 assert!(seq.get_item(10).is_err());
488 });
489 }
490
491 #[test]
492 fn test_seq_index_trait() {
493 Python::with_gil(|py| {
494 let v: Vec<i32> = vec![1, 1, 2];
495 let ob = v.to_object(py);
496 let seq = ob.downcast::<PySequence>(py).unwrap();
497 assert_eq!(1, seq[0].extract::<i32>().unwrap());
498 assert_eq!(1, seq[1].extract::<i32>().unwrap());
499 assert_eq!(2, seq[2].extract::<i32>().unwrap());
500 });
501 }
502
503 #[test]
504 #[should_panic = "index 7 out of range for sequence"]
505 fn test_seq_index_trait_panic() {
506 Python::with_gil(|py| {
507 let v: Vec<i32> = vec![1, 1, 2];
508 let ob = v.to_object(py);
509 let seq = ob.downcast::<PySequence>(py).unwrap();
510 let _ = &seq[7];
511 });
512 }
513
514 #[test]
515 fn test_seq_index_trait_ranges() {
516 Python::with_gil(|py| {
517 let v: Vec<i32> = vec![1, 1, 2];
518 let ob = v.to_object(py);
519 let seq = ob.downcast::<PySequence>(py).unwrap();
520 assert_eq!(vec![1, 2], seq[1..3].extract::<Vec<i32>>().unwrap());
521 assert_eq!(Vec::<i32>::new(), seq[3..3].extract::<Vec<i32>>().unwrap());
522 assert_eq!(vec![1, 2], seq[1..].extract::<Vec<i32>>().unwrap());
523 assert_eq!(Vec::<i32>::new(), seq[3..].extract::<Vec<i32>>().unwrap());
524 assert_eq!(vec![1, 1, 2], seq[..].extract::<Vec<i32>>().unwrap());
525 assert_eq!(vec![1, 2], seq[1..=2].extract::<Vec<i32>>().unwrap());
526 assert_eq!(vec![1, 1], seq[..2].extract::<Vec<i32>>().unwrap());
527 assert_eq!(vec![1, 1], seq[..=1].extract::<Vec<i32>>().unwrap());
528 })
529 }
530
531 #[test]
532 #[should_panic = "range start index 5 out of range for sequence of length 3"]
533 fn test_seq_index_trait_range_panic_start() {
534 Python::with_gil(|py| {
535 let v: Vec<i32> = vec![1, 1, 2];
536 let ob = v.to_object(py);
537 let seq = ob.downcast::<PySequence>(py).unwrap();
538 seq[5..10].extract::<Vec<i32>>().unwrap();
539 })
540 }
541
542 #[test]
543 #[should_panic = "range end index 10 out of range for sequence of length 3"]
544 fn test_seq_index_trait_range_panic_end() {
545 Python::with_gil(|py| {
546 let v: Vec<i32> = vec![1, 1, 2];
547 let ob = v.to_object(py);
548 let seq = ob.downcast::<PySequence>(py).unwrap();
549 seq[1..10].extract::<Vec<i32>>().unwrap();
550 })
551 }
552
553 #[test]
554 #[should_panic = "slice index starts at 2 but ends at 1"]
555 fn test_seq_index_trait_range_panic_wrong_order() {
556 Python::with_gil(|py| {
557 let v: Vec<i32> = vec![1, 1, 2];
558 let ob = v.to_object(py);
559 let seq = ob.downcast::<PySequence>(py).unwrap();
560 #[allow(clippy::reversed_empty_ranges)]
561 seq[2..1].extract::<Vec<i32>>().unwrap();
562 })
563 }
564
565 #[test]
566 #[should_panic = "range start index 8 out of range for sequence of length 3"]
567 fn test_seq_index_trait_range_from_panic() {
568 Python::with_gil(|py| {
569 let v: Vec<i32> = vec![1, 1, 2];
570 let ob = v.to_object(py);
571 let seq = ob.downcast::<PySequence>(py).unwrap();
572 seq[8..].extract::<Vec<i32>>().unwrap();
573 })
574 }
575
576 #[test]
577 fn test_seq_del_item() {
578 Python::with_gil(|py| {
579 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
580 let ob = v.to_object(py);
581 let seq = ob.downcast::<PySequence>(py).unwrap();
582 assert!(seq.del_item(10).is_err());
583 assert_eq!(1, seq[0].extract::<i32>().unwrap());
584 assert!(seq.del_item(0).is_ok());
585 assert_eq!(1, seq[0].extract::<i32>().unwrap());
586 assert!(seq.del_item(0).is_ok());
587 assert_eq!(2, seq[0].extract::<i32>().unwrap());
588 assert!(seq.del_item(0).is_ok());
589 assert_eq!(3, seq[0].extract::<i32>().unwrap());
590 assert!(seq.del_item(0).is_ok());
591 assert_eq!(5, seq[0].extract::<i32>().unwrap());
592 assert!(seq.del_item(0).is_ok());
593 assert_eq!(8, seq[0].extract::<i32>().unwrap());
594 assert!(seq.del_item(0).is_ok());
595 assert_eq!(0, seq.len().unwrap());
596 assert!(seq.del_item(0).is_err());
597 });
598 }
599
600 #[test]
601 fn test_seq_set_item() {
602 Python::with_gil(|py| {
603 let v: Vec<i32> = vec![1, 2];
604 let ob = v.to_object(py);
605 let seq = ob.downcast::<PySequence>(py).unwrap();
606 assert_eq!(2, seq[1].extract::<i32>().unwrap());
607 assert!(seq.set_item(1, 10).is_ok());
608 assert_eq!(10, seq[1].extract::<i32>().unwrap());
609 });
610 }
611
612 #[test]
613 fn test_seq_set_item_refcnt() {
614 let obj = get_object();
615
616 Python::with_gil(|py| {
617 let v: Vec<i32> = vec![1, 2];
618 let ob = v.to_object(py);
619 let seq = ob.downcast::<PySequence>(py).unwrap();
620 assert!(seq.set_item(1, &obj).is_ok());
621 assert!(seq[1].as_ptr() == obj.as_ptr());
622 });
623
624 Python::with_gil(|py| {
625 assert_eq!(1, obj.get_refcnt(py));
626 });
627 }
628
629 #[test]
630 fn test_seq_get_slice() {
631 Python::with_gil(|py| {
632 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
633 let ob = v.to_object(py);
634 let seq = ob.downcast::<PySequence>(py).unwrap();
635 assert_eq!(
636 [1, 2, 3],
637 seq.get_slice(1, 4).unwrap().extract::<[i32; 3]>().unwrap()
638 );
639 assert_eq!(
640 [3, 5, 8],
641 seq.get_slice(3, 100)
642 .unwrap()
643 .extract::<[i32; 3]>()
644 .unwrap()
645 );
646 });
647 }
648
649 #[test]
650 fn test_set_slice() {
651 Python::with_gil(|py| {
652 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
653 let w: Vec<i32> = vec![7, 4];
654 let ob = v.to_object(py);
655 let seq = ob.downcast::<PySequence>(py).unwrap();
656 let ins = w.to_object(py);
657 seq.set_slice(1, 4, ins.as_ref(py)).unwrap();
658 assert_eq!([1, 7, 4, 5, 8], seq.extract::<[i32; 5]>().unwrap());
659 seq.set_slice(3, 100, PyList::empty(py)).unwrap();
660 assert_eq!([1, 7, 4], seq.extract::<[i32; 3]>().unwrap());
661 });
662 }
663
664 #[test]
665 fn test_del_slice() {
666 Python::with_gil(|py| {
667 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
668 let ob = v.to_object(py);
669 let seq = ob.downcast::<PySequence>(py).unwrap();
670 seq.del_slice(1, 4).unwrap();
671 assert_eq!([1, 5, 8], seq.extract::<[i32; 3]>().unwrap());
672 seq.del_slice(1, 100).unwrap();
673 assert_eq!([1], seq.extract::<[i32; 1]>().unwrap());
674 });
675 }
676
677 #[test]
678 fn test_seq_index() {
679 Python::with_gil(|py| {
680 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
681 let ob = v.to_object(py);
682 let seq = ob.downcast::<PySequence>(py).unwrap();
683 assert_eq!(0, seq.index(1i32).unwrap());
684 assert_eq!(2, seq.index(2i32).unwrap());
685 assert_eq!(3, seq.index(3i32).unwrap());
686 assert_eq!(4, seq.index(5i32).unwrap());
687 assert_eq!(5, seq.index(8i32).unwrap());
688 assert!(seq.index(42i32).is_err());
689 });
690 }
691
692 #[test]
693 #[cfg(not(PyPy))]
694 fn test_seq_count() {
695 Python::with_gil(|py| {
696 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
697 let ob = v.to_object(py);
698 let seq = ob.downcast::<PySequence>(py).unwrap();
699 assert_eq!(2, seq.count(1i32).unwrap());
700 assert_eq!(1, seq.count(2i32).unwrap());
701 assert_eq!(1, seq.count(3i32).unwrap());
702 assert_eq!(1, seq.count(5i32).unwrap());
703 assert_eq!(1, seq.count(8i32).unwrap());
704 assert_eq!(0, seq.count(42i32).unwrap());
705 });
706 }
707
708 #[test]
709 fn test_seq_iter() {
710 Python::with_gil(|py| {
711 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
712 let ob = v.to_object(py);
713 let seq = ob.downcast::<PySequence>(py).unwrap();
714 let mut idx = 0;
715 for el in seq.iter().unwrap() {
716 assert_eq!(v[idx], el.unwrap().extract::<i32>().unwrap());
717 idx += 1;
718 }
719 assert_eq!(idx, v.len());
720 });
721 }
722
723 #[test]
724 fn test_seq_strings() {
725 Python::with_gil(|py| {
726 let v = vec!["It", "was", "the", "worst", "of", "times"];
727 let ob = v.to_object(py);
728 let seq = ob.downcast::<PySequence>(py).unwrap();
729
730 let bad_needle = "blurst".to_object(py);
731 assert!(!seq.contains(bad_needle).unwrap());
732
733 let good_needle = "worst".to_object(py);
734 assert!(seq.contains(good_needle).unwrap());
735 });
736 }
737
738 #[test]
739 fn test_seq_concat() {
740 Python::with_gil(|py| {
741 let v: Vec<i32> = vec![1, 2, 3];
742 let ob = v.to_object(py);
743 let seq = ob.downcast::<PySequence>(py).unwrap();
744 let concat_seq = seq.concat(seq).unwrap();
745 assert_eq!(6, concat_seq.len().unwrap());
746 let concat_v: Vec<i32> = vec![1, 2, 3, 1, 2, 3];
747 for (el, cc) in concat_seq.iter().unwrap().zip(concat_v) {
748 assert_eq!(cc, el.unwrap().extract::<i32>().unwrap());
749 }
750 });
751 }
752
753 #[test]
754 fn test_seq_concat_string() {
755 Python::with_gil(|py| {
756 let v = "string";
757 let ob = v.to_object(py);
758 let seq = ob.downcast::<PySequence>(py).unwrap();
759 let concat_seq = seq.concat(seq).unwrap();
760 assert_eq!(12, concat_seq.len().unwrap());
761 let concat_v = "stringstring".to_owned();
762 for (el, cc) in seq.iter().unwrap().zip(concat_v.chars()) {
763 assert_eq!(cc, el.unwrap().extract::<char>().unwrap());
764 }
765 });
766 }
767
768 #[test]
769 fn test_seq_repeat() {
770 Python::with_gil(|py| {
771 let v = vec!["foo", "bar"];
772 let ob = v.to_object(py);
773 let seq = ob.downcast::<PySequence>(py).unwrap();
774 let repeat_seq = seq.repeat(3).unwrap();
775 assert_eq!(6, repeat_seq.len().unwrap());
776 let repeated = ["foo", "bar", "foo", "bar", "foo", "bar"];
777 for (el, rpt) in repeat_seq.iter().unwrap().zip(repeated.iter()) {
778 assert_eq!(*rpt, el.unwrap().extract::<String>().unwrap());
779 }
780 });
781 }
782
783 #[test]
784 fn test_seq_inplace() {
785 Python::with_gil(|py| {
786 let v = vec!["foo", "bar"];
787 let ob = v.to_object(py);
788 let seq = ob.downcast::<PySequence>(py).unwrap();
789 let rep_seq = seq.in_place_repeat(3).unwrap();
790 assert_eq!(6, seq.len().unwrap());
791 assert!(seq.is(rep_seq));
792
793 let conc_seq = seq.in_place_concat(seq).unwrap();
794 assert_eq!(12, seq.len().unwrap());
795 assert!(seq.is(conc_seq));
796 });
797 }
798
799 #[test]
800 fn test_list_coercion() {
801 Python::with_gil(|py| {
802 let v = vec!["foo", "bar"];
803 let ob = v.to_object(py);
804 let seq = ob.downcast::<PySequence>(py).unwrap();
805 assert!(seq.to_list().unwrap().eq(PyList::new(py, &v)).unwrap());
806 #[allow(deprecated)]
807 {
808 assert!(seq.list().is_ok());
809 }
810 });
811 }
812
813 #[test]
814 fn test_strings_coerce_to_lists() {
815 Python::with_gil(|py| {
816 let v = "foo";
817 let ob = v.to_object(py);
818 let seq: &PySequence = ob.downcast(py).unwrap();
819 assert!(seq
820 .to_list()
821 .unwrap()
822 .eq(PyList::new(py, ["f", "o", "o"]))
823 .unwrap());
824 #[allow(deprecated)]
825 {
826 assert!(seq.list().is_ok());
827 }
828 });
829 }
830
831 #[test]
832 fn test_tuple_coercion() {
833 Python::with_gil(|py| {
834 let v = ("foo", "bar");
835 let ob = v.to_object(py);
836 let seq = ob.downcast::<PySequence>(py).unwrap();
837 assert!(seq
838 .to_tuple()
839 .unwrap()
840 .eq(PyTuple::new(py, ["foo", "bar"]))
841 .unwrap());
842 #[allow(deprecated)]
843 {
844 assert!(seq.tuple().is_ok());
845 }
846 });
847 }
848
849 #[test]
850 fn test_lists_coerce_to_tuples() {
851 Python::with_gil(|py| {
852 let v = vec!["foo", "bar"];
853 let ob = v.to_object(py);
854 let seq = ob.downcast::<PySequence>(py).unwrap();
855 assert!(seq.to_tuple().unwrap().eq(PyTuple::new(py, &v)).unwrap());
856 #[allow(deprecated)]
857 {
858 assert!(seq.tuple().is_ok());
859 }
860 });
861 }
862
863 #[test]
864 fn test_extract_tuple_to_vec() {
865 Python::with_gil(|py| {
866 let v: Vec<i32> = py.eval("(1, 2)", None, None).unwrap().extract().unwrap();
867 assert!(v == [1, 2]);
868 });
869 }
870
871 #[test]
872 fn test_extract_range_to_vec() {
873 Python::with_gil(|py| {
874 let v: Vec<i32> = py
875 .eval("range(1, 5)", None, None)
876 .unwrap()
877 .extract()
878 .unwrap();
879 assert!(v == [1, 2, 3, 4]);
880 });
881 }
882
883 #[test]
884 fn test_extract_bytearray_to_vec() {
885 Python::with_gil(|py| {
886 let v: Vec<u8> = py
887 .eval("bytearray(b'abc')", None, None)
888 .unwrap()
889 .extract()
890 .unwrap();
891 assert!(v == b"abc");
892 });
893 }
894
895 #[test]
896 fn test_seq_downcast_unchecked() {
897 Python::with_gil(|py| {
898 let v = vec!["foo", "bar"];
899 let ob = v.to_object(py);
900 let seq = ob.downcast::<PySequence>(py).unwrap();
901 let type_ptr = seq.as_ref();
902 let seq_from = unsafe { type_ptr.downcast_unchecked::<PySequence>() };
903 assert!(seq_from.to_list().is_ok());
904 });
905 }
906
907 #[test]
908 fn test_as_ref() {
909 Python::with_gil(|py| {
910 let seq: Py<PySequence> = PyList::empty(py).as_sequence().into();
911 let seq_ref: &PySequence = seq.as_ref(py);
912 assert_eq!(seq_ref.len().unwrap(), 0);
913 })
914 }
915
916 #[test]
917 fn test_into_ref() {
918 Python::with_gil(|py| {
919 let bare_seq = PyList::empty(py).as_sequence();
920 assert_eq!(bare_seq.get_refcnt(), 1);
921 let seq: Py<PySequence> = bare_seq.into();
922 assert_eq!(bare_seq.get_refcnt(), 2);
923 let seq_ref = seq.into_ref(py);
924 assert_eq!(seq_ref.len().unwrap(), 0);
925 assert_eq!(seq_ref.get_refcnt(), 2);
926 })
927 }
928}
929