Skip to content

Commit 5d227fc

Browse files
authored
Use dir instead of getmembers (#879)
* Use dir instead of getmembers * Add property decorator tests * Use cpython api function for dir * Don't try to test properties * Check if return value is NULL * Deprecate keys * Add deprecation test
1 parent ead312f commit 5d227fc

File tree

2 files changed

+12
-4
lines changed

2 files changed

+12
-4
lines changed

src/PyCall.jl

+6-3
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,11 @@ function trygetproperty(o::PyObject, s::AbstractString, d)
316316
return p == C_NULL ? d : PyObject(p)
317317
end
318318

319-
propertynames(o::PyObject) = ispynull(o) ? Symbol[] : map(x->Symbol(first(x)), PyIterator{PyObject}(pycall(inspect."getmembers", PyObject, o)))
319+
function propertynames(o::PyObject)
320+
ispynull(o) && return Symbol[]
321+
names = @pycheckn ccall((@pysym :PyObject_Dir), PyObject, (PyPtr,), o)
322+
return convert(Vector{Symbol}, names)
323+
end
320324

321325
# avoiding method ambiguity
322326
setproperty!(o::PyObject, s::Symbol, v) = _setproperty!(o,s,v)
@@ -366,8 +370,7 @@ hasproperty(o::PyObject, s::AbstractString) = pyhasproperty(o, s)
366370

367371
#########################################################################
368372

369-
keys(o::PyObject) = Symbol[m[1] for m in pycall(inspect."getmembers",
370-
PyVector{Tuple{Symbol,PyObject}}, o)]
373+
@deprecate keys(o::PyObject) propertynames(o)
371374

372375
#########################################################################
373376
# Create anonymous composite w = pywrap(o) wrapping the object o

test/runtests.jl

+6-1
Original file line numberDiff line numberDiff line change
@@ -295,17 +295,22 @@ const PyInt = pyversion < v"3" ? Int : Clonglong
295295
class A:
296296
class B:
297297
C = 1
298+
@property
299+
def D(self):
300+
raise NotImplementedError
298301
"""
299302
A = py"A"
300303
@test hasproperty(A, "B")
301304
@test getproperty(A, "B") == py"A.B"
302305
@test :B in propertynames(A)
303306
@static if VERSION >= v"0.7-"
307+
@test :D in propertynames(A.B)
304308
@test A.B.C == 1
305309
@test_throws KeyError A.X
306310
end
307311
setproperty!(py"A.B", "C", 2)
308312
@test py"A.B.C" == 2
313+
@test_deprecated keys(A)
309314

310315
# buffers
311316
let b = PyCall.PyBuffer(pyutf8("test string"))
@@ -317,7 +322,7 @@ const PyInt = pyversion < v"3" ? Int : Clonglong
317322

318323
let o = PyObject(1+2im)
319324
@test PyCall.hasproperty(o, :real) # replace by Base.hasproperty in the future
320-
@test :real in keys(o)
325+
@test :real in propertynames(o)
321326
@test o.real == 1
322327
end
323328

0 commit comments

Comments
 (0)