Skip to content

Commit 34d3f55

Browse files
authored
add method pynext(x, d) (#783)
Co-authored-by: Christopher Rowley <github.com/cjdoris>
1 parent 241709d commit 34d3f55

3 files changed

Lines changed: 60 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Changelog
22

33
## Unreleased
4-
* Added option `lib` to JuliaCall. Setting this will skip the discovery subprocess.
4+
* Add method `pynext(x, d)` to return a default value `d` if there are no more elements.
5+
* Add option `lib` to JuliaCall. Setting this will skip the discovery subprocess.
56
* Bug fixes.
67

78
## 0.9.34 (2026-05-18)

src/Core/builtins.jl

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,11 +507,27 @@ Equivalent to `iter(x)` in Python.
507507
pyiter(x) = pynew(errcheck(@autopy x C.PyObject_GetIter(x_)))
508508

509509
"""
510-
pynext(x)
510+
pynext(x, [d])
511511
512-
Equivalent to `next(x)` in Python.
512+
Equivalent to `next(x, d)` in Python.
513+
514+
Returns the next item from the iterator `x`. If there are no more items, returns `d` if
515+
given, else raises `StopIteration`.
513516
"""
514-
pynext(x) = pybuiltins.next(x)
517+
function pynext(x)
518+
ptr = errcheck_ambig(C.PyIter_Next(x))
519+
if ptr == C.PyNULL
520+
errset(pybuiltins.StopIteration)
521+
pythrow()
522+
else
523+
pynew(ptr)
524+
end
525+
end
526+
527+
function pynext(x, d)
528+
ptr = errcheck_ambig(C.PyIter_Next(x))
529+
ptr == C.PyNULL ? d : pynew(ptr)
530+
end
515531

516532
"""
517533
unsafe_pynext(x)

test/Core.jl

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -223,25 +223,45 @@
223223
end
224224

225225
@testitem "iter" begin
226-
@test_throws PyException pyiter(pybuiltins.None)
227-
@test_throws PyException pyiter(pybuiltins.True)
228-
# unsafe_pynext
229-
it = pyiter(pyrange(2))
230-
x = PythonCall.unsafe_pynext(it)
231-
@test !PythonCall.pyisnull(x)
232-
@test pyeq(Bool, x, 0)
233-
x = PythonCall.unsafe_pynext(it)
234-
@test !PythonCall.pyisnull(x)
235-
@test pyeq(Bool, x, 1)
236-
x = PythonCall.unsafe_pynext(it)
237-
@test PythonCall.pyisnull(x)
238-
# pynext
239-
it = pyiter(pyrange(2))
240-
x = pynext(it)
241-
@test pyeq(Bool, x, 0)
242-
x = pynext(it)
243-
@test pyeq(Bool, x, 1)
244-
@test_throws PyException pynext(it)
226+
@testset "non-iterables" begin
227+
@test_throws PyException pyiter(pybuiltins.None)
228+
@test_throws PyException pyiter(pybuiltins.True)
229+
end
230+
@testset "unsafe_pynext" begin
231+
it = pyiter(pyrange(2))
232+
x = PythonCall.unsafe_pynext(it)
233+
@test x isa Py
234+
@test !PythonCall.pyisnull(x)
235+
@test pyeq(Bool, x, 0)
236+
x = PythonCall.unsafe_pynext(it)
237+
@test x isa Py
238+
@test !PythonCall.pyisnull(x)
239+
@test pyeq(Bool, x, 1)
240+
x = PythonCall.unsafe_pynext(it)
241+
@test x isa Py
242+
@test PythonCall.pyisnull(x)
243+
end
244+
@testset "pynext" begin
245+
it = pyiter(pyrange(2))
246+
x = pynext(it)
247+
@test x isa Py
248+
@test pyeq(Bool, x, 0)
249+
x = pynext(it)
250+
@test x isa Py
251+
@test pyeq(Bool, x, 1)
252+
@test_throws PyException pynext(it)
253+
end
254+
@testset "pynext with default" begin
255+
it = pyiter(pyrange(2))
256+
x = pynext(it, nothing)
257+
@test x isa Py
258+
@test pyeq(Bool, x, 0)
259+
x = pynext(it, nothing)
260+
@test x isa Py
261+
@test pyeq(Bool, x, 1)
262+
x = pynext(it, nothing)
263+
@test x === nothing
264+
end
245265
end
246266

247267
@testitem "number" begin

0 commit comments

Comments
 (0)