Skip to content

Commit deb7570

Browse files
authored
remove unsafe API: getptr, pycopy!, pyisnull, pynew, PyNULL, unsafe_pynext (#786)
* remove unsafe API: getptr, pycopy!, pyisnull, pynew, PyNULL, unsafe_pynext * remove removed functions from docs --------- Co-authored-by: Christopher Rowley <github.com/cjdoris>
1 parent 8161918 commit deb7570

8 files changed

Lines changed: 51 additions & 35 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* Comparisons like `==`, `<` and `isless` between `Py`s now return `Bool` instead of `Py`.
77
* Removed comparisons between `Py` and `Number` (like `Py(3) < 5`).
88
* Removed arithmetic between `Py` and `Number` (like `Py(2) * 10`).
9+
* Removed unsafe API: `getptr`, `pycopy!`, `pyisnull`, `pynew`, `PyNULL`, `unsafe_pynext`.
10+
A `Py` is now always a valid, fixed, non-NULL Python object in the documented API.
911
* Python errors no longer automatically set `sys.last_traceback` etc. when displayed from Julia.
1012
* Removed `CONFIG.auto_sys_last_traceback`.
1113
* Changes to `PythonCall.GC` (now more like `Base.GC`):

docs/src/pythoncall-reference.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,7 @@ The functions here are not exported. They are mostly unsafe in the sense that yo
250250
crash Julia by using them incorrectly.
251251

252252
```@docs
253-
PythonCall.pynew
254-
PythonCall.pyisnull
255-
PythonCall.pycopy!
256-
PythonCall.getptr
257253
PythonCall.pydel!
258-
PythonCall.unsafe_pynext
259254
```
260255

261256
## NumpyDates

docs/src/v1-migration-guide.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,41 @@ between Python and Julia is explicit.
2424
* Instead of `Py(5) * 6` use `Py(5) * Py(6)` or `pymul(Py(5), 6)`.
2525
* Instead of `np.array([1,2,3]) < 3` use `pylt(np.array([1,2,3]), 3)`.
2626

27+
The unsafe API has been removed: `getptr`, `pycopy!`, `pyisnull`, `pynew`, `PyNULL`,
28+
`unsafe_pynext`. This means that a `Py` is immutable and non-NULL in the documented API
29+
for PythonCall (mutability and NULLs are internal implementation details). These functions
30+
were primarily used in packages to have global `Py` objects with this pattern:
31+
32+
```
33+
module Foo
34+
using PythonCall
35+
36+
const np = PythonCall.pynew()
37+
38+
function __init__()
39+
PythonCall.pycopy!(np, pyimport("numpy"))
40+
end
41+
end
42+
```
43+
44+
We have recommended this alternate, safe pattern for a while now:
45+
46+
```
47+
module Foo
48+
using PythonCall
49+
50+
const np = Ref{Py}()
51+
52+
function __init__()
53+
np[] = pyimport("numpy")
54+
end
55+
end
56+
```
57+
58+
* Instead of `PythonCall.pynew()` use `Ref{Py}()`.
59+
* Instead of `PythonCall.pycopy!(x, y)` use `x[] = y`.
60+
* Instead of `PythonCall.unsafe_pynext(x)` (and check for `pyisnull`) use `pynext(x, nothing)` (and check for `nothing`).
61+
2762
When a Python error is displayed in Julia, PythonCall no longer sets `sys.last_traceback`
2863
and friends. This means that the Python post-mortem debugger `pdb.pm()` will no longer
2964
work.

src/API/functions.jl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ function python_library_path end
55
function python_version end
66

77
# Core
8-
function getptr end
98
function ispy end
109
function pyabs end
1110
function pyadd end
@@ -21,7 +20,6 @@ function pycollist end
2120
function pycompile end
2221
function pycomplex end
2322
function pycontains end
24-
function pycopy! end
2523
function pydate end
2624
function pydatetime end
2725
function pydel! end
@@ -62,7 +60,6 @@ function pyipow end
6260
function pyirshift end
6361
function pyis end
6462
function pyisinstance end
65-
function pyisnull end
6663
function pyissubclass end
6764
function pyisub end
6865
function pyiter end
@@ -78,7 +75,6 @@ function pymod end
7875
function pymul end
7976
function pyne end
8077
function pyneg end
81-
function pynew end
8278
function pynext end
8379
function pynot end
8480
function pyor end
@@ -102,7 +98,6 @@ function pytuple end
10298
function pytype end
10399
function pywith end
104100
function pyxor end
105-
function unsafe_pynext end
106101

107102
# Convert
108103
function pyconvert end

src/API/publics.jl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,7 @@ if Base.VERSION ≥ v"1.11"
1313
1414
# Core
1515
CONFIG,
16-
getptr,
17-
pycopy!,
1816
pydel!,
19-
pyisnull,
20-
pynew,
21-
PyNULL,
22-
unsafe_pynext,
2317
2418
# Compat
2519
event_loop_off,

src/Core/Core.jl

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import ..PythonCall:
3434
@pyconst,
3535
@pyeval,
3636
@pyexec,
37-
getptr,
3837
ispy,
3938
Py,
4039
pyabs,
@@ -53,7 +52,6 @@ import ..PythonCall:
5352
pycomplex,
5453
pycontains,
5554
pyconvert,
56-
pycopy!,
5755
pydate,
5856
pydatetime,
5957
pydel!,
@@ -95,7 +93,6 @@ import ..PythonCall:
9593
pyirshift,
9694
pyis,
9795
pyisinstance,
98-
pyisnull,
9996
pyissubclass,
10097
pyisub,
10198
pyiter,
@@ -111,7 +108,6 @@ import ..PythonCall:
111108
pymul,
112109
pyne,
113110
pyneg,
114-
pynew,
115111
pynext,
116112
pynot,
117113
pyor,
@@ -134,8 +130,7 @@ import ..PythonCall:
134130
pytuple,
135131
pytype,
136132
pywith,
137-
pyxor,
138-
unsafe_pynext
133+
pyxor
139134

140135
export
141136
_base_datetime,

src/PythonCall.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ include("JlWrap/JlWrap.jl")
1616
include("Compat/Compat.jl")
1717

1818
# non-exported API
19-
using .Core: PyNULL, CONFIG
19+
using .Core: CONFIG
2020

2121
# not API but used in tests
2222
for k in [

test/Core.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import Markdown
33
@testset "pyis" begin
44
x = pylist()
5-
y = PythonCall.pynew(x)
5+
y = PythonCall.Core.pynew(x)
66
z = pylist()
77
@test pyis(x, x)
88
@test pyis(x, y)
@@ -218,7 +218,7 @@
218218
@test Base.Docs.getdoc(Py(nothing)) isa Markdown.MD
219219
@test Base.Docs.getdoc(Py(12)) isa Markdown.MD
220220
@test Base.Docs.getdoc(pybuiltins.int) isa Markdown.MD
221-
@test Base.Docs.getdoc(PythonCall.PyNULL) === nothing
221+
@test Base.Docs.getdoc(PythonCall.Core.PyNULL) === nothing
222222
end
223223
@testset "comparisons" begin
224224
@testset "Py vs Py" begin
@@ -255,14 +255,14 @@ end
255255
@test_throws PyException pyiter(pybuiltins.True)
256256
# unsafe_pynext
257257
it = pyiter(pyrange(2))
258-
x = PythonCall.unsafe_pynext(it)
259-
@test !PythonCall.pyisnull(x)
258+
x = PythonCall.Core.unsafe_pynext(it)
259+
@test !PythonCall.Core.pyisnull(x)
260260
@test pyeq(Bool, x, 0)
261-
x = PythonCall.unsafe_pynext(it)
262-
@test !PythonCall.pyisnull(x)
261+
x = PythonCall.Core.unsafe_pynext(it)
262+
@test !PythonCall.Core.pyisnull(x)
263263
@test pyeq(Bool, x, 1)
264-
x = PythonCall.unsafe_pynext(it)
265-
@test PythonCall.pyisnull(x)
264+
x = PythonCall.Core.unsafe_pynext(it)
265+
@test PythonCall.Core.pyisnull(x)
266266
# pynext
267267
it = pyiter(pyrange(2))
268268
x = pynext(it)
@@ -825,18 +825,18 @@ end
825825
@test showable(MIME("text/plain"), Py(nothing))
826826
@test showable(MIME("text/plain"), Py(12))
827827
# https://github.com/JuliaPy/PythonCall.jl/issues/522
828-
@test showable(MIME("text/plain"), PythonCall.pynew())
829-
@test !showable(MIME("text/html"), PythonCall.pynew())
828+
@test showable(MIME("text/plain"), PythonCall.Core.pynew())
829+
@test !showable(MIME("text/html"), PythonCall.Core.pynew())
830830
end
831831
@testset "show" begin
832832
@test sprint(show, MIME("text/plain"), Py(nothing)) == "Python: None"
833833
@test sprint(show, MIME("text/plain"), Py(12)) == "Python: 12"
834834
# https://github.com/JuliaPy/PythonCall.jl/issues/522
835-
@test sprint(show, MIME("text/plain"), PythonCall.pynew()) == "Python: NULL"
835+
@test sprint(show, MIME("text/plain"), PythonCall.Core.pynew()) == "Python: NULL"
836836
# test compact printing
837837
@test sprint(show, MIME("text/plain"), Py(String('A':'Z')), context=(:compact=>true, :displaysize=>(50, 20))) == "Py: 'ABCDE ... WXYZ'"
838838
@test sprint(show, MIME("text/plain"), Py(String('A':'Z')), context=(:compact=>true, :limit=>false, :displaysize=>(50, 20))) == "Py: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"
839-
@test_throws MethodError sprint(show, MIME("text/html"), PythonCall.pynew())
839+
@test_throws MethodError sprint(show, MIME("text/html"), PythonCall.Core.pynew())
840840
end
841841
end
842842

0 commit comments

Comments
 (0)