Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix depwarn on 0.5 #267

Merged
merged 1 commit into from May 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion REQUIRE
@@ -1,4 +1,4 @@
julia 0.4
Compat 0.7.14
Compat 0.7.15
Conda 0.1.6
MacroTools 0.2
7 changes: 4 additions & 3 deletions src/PyCall.jl
Expand Up @@ -24,6 +24,7 @@ import Base: sigatomic_begin, sigatomic_end

## Compatibility import for v0.4, v0.5
using Compat
import Compat.String
import Base.unsafe_convert

#########################################################################
Expand Down Expand Up @@ -286,7 +287,7 @@ keys(o::PyObject) = Symbol[m[1] for m in pycall(inspect["getmembers"],
# and providing access to o's members (converted to PyAny) as w.member.

# we skip wrapping Julia reserved words (which cannot be type members)
const reserved = Set{ASCIIString}(["while", "if", "for", "try", "return", "break", "continue", "function", "macro", "quote", "let", "local", "global", "const", "abstract", "typealias", "type", "bitstype", "immutable", "ccall", "do", "module", "baremodule", "using", "import", "export", "importall", "pymember", "false", "true", "Tuple"])
const reserved = Set{String}(["while", "if", "for", "try", "return", "break", "continue", "function", "macro", "quote", "let", "local", "global", "const", "abstract", "typealias", "type", "bitstype", "immutable", "ccall", "do", "module", "baremodule", "using", "import", "export", "importall", "pymember", "false", "true", "Tuple"])

"""
pywrap(o::PyObject)
Expand All @@ -302,11 +303,11 @@ function pywrap(o::PyObject, mname::Symbol=:__anon__)
pycall(inspect["getmembers"], PyObject, o))
filter!(m -> !(m[1] in reserved), members)
m = Module(mname, false)
consts = [Expr(:const, Expr(:(=), symbol(x[1]), convert(PyAny, x[2]))) for x in members]
consts = [Expr(:const, Expr(:(=), Symbol(x[1]), convert(PyAny, x[2]))) for x in members]
exports = try
convert(Vector{Symbol}, o["__all__"])
catch
[symbol(x[1]) for x in filter(x -> x[1][1] != '_', members)]
[Symbol(x[1]) for x in filter(x -> x[1][1] != '_', members)]
end
eval(m, Expr(:toplevel, consts..., :(pymember(s) = $(getindex)($(o), s)),
Expr(:export, exports...)))
Expand Down
15 changes: 5 additions & 10 deletions src/conversions.jl
Expand Up @@ -58,14 +58,9 @@ convert(::Type{Void}, po::PyObject) = nothing
#########################################################################
# String conversions (both bytes arrays and unicode strings)

PyObject(s::UTF8String) =
PyObject(@pycheckn ccall(@pysym(PyUnicode_DecodeUTF8),
PyPtr, (Ptr{UInt8}, Int, Ptr{UInt8}),
s, sizeof(s), C_NULL))

function PyObject(s::AbstractString)
sb = bytestring(s)
if pyunicode_literals
sb = String(s)
if pyunicode_literals || !isascii(sb)
PyObject(@pycheckn ccall(@pysym(PyUnicode_DecodeUTF8),
PyPtr, (Ptr{UInt8}, Int, Ptr{UInt8}),
sb, sizeof(sb), C_NULL))
Expand All @@ -92,7 +87,7 @@ end
# TODO: should symbols be converted to a subclass of Python strings/bytes,
# so that PyAny conversion can convert it back to a Julia symbol?
PyObject(s::Symbol) = PyObject(string(s))
convert(::Type{Symbol}, po::PyObject) = symbol(convert(AbstractString, po))
convert(::Type{Symbol}, po::PyObject) = Symbol(convert(AbstractString, po))

#########################################################################
# ByteArray conversions
Expand Down Expand Up @@ -621,7 +616,7 @@ function mpmath_init()
copy!(mpf, mpmath["mpf"])
copy!(mpc, mpmath["mpc"])
end
curprec = get_bigfloat_precision()
curprec = precision(BigFloat)
if mpprec[1] != curprec
mpprec[1] = curprec
mpmath["mp"]["prec"] = mpprec[1]
Expand Down Expand Up @@ -702,7 +697,7 @@ pyfloat_query(o::PyObject) = pyisinstance(o, @pyglobalobj :PyFloat_Type) || pyi
pycomplex_query(o::PyObject) =
pyisinstance(o, @pyglobalobj :PyComplex_Type) || pyisinstance(o, npy_complexfloating) ? Complex128 : Union{}

pystring_query(o::PyObject) = pyisinstance(o, @pyglobalobj PyString_Type) ? AbstractString : pyisinstance(o, @pyglobalobj :PyUnicode_Type) ? UTF8String : Union{}
pystring_query(o::PyObject) = pyisinstance(o, @pyglobalobj PyString_Type) ? AbstractString : pyisinstance(o, @pyglobalobj :PyUnicode_Type) ? String : Union{}

# Given call overloading, all PyObjects are callable already, so
# we never automatically convert to Function.
Expand Down
2 changes: 1 addition & 1 deletion src/numpy.jl
Expand Up @@ -85,7 +85,7 @@ function npyinitialize()
end
API = pointer_to_array(PyArray_API, (PyArray_API_length,))
for m in eachmatch(r, hdr) # build npy_api table
npy_api[symbol(m.captures[1])] = API[parse(Int, m.captures[2])+1]
npy_api[Symbol(m.captures[1])] = API[parse(Int, m.captures[2])+1]
end
if !haskey(npy_api, :PyArray_New)
error("failure parsing NumPy PyArray_API symbol table")
Expand Down
2 changes: 1 addition & 1 deletion src/pyclass.jl
Expand Up @@ -105,7 +105,7 @@ function parse_pydef(expr)
else
error("$access is not a valid accessor; must be either get or set!")
end
jl_fun_name = gensym(symbol(attribute,:_,access))
jl_fun_name = gensym(Symbol(attribute,:_,access))
push!(function_defs, :(function $jl_fun_name($(args...))
$rhs
end))
Expand Down
4 changes: 2 additions & 2 deletions src/pydates.jl
Expand Up @@ -98,8 +98,8 @@ function PyObject(p::Dates.Millisecond)
end

for T in (:Date, :DateTime, :Delta)
f = symbol(string("Py", T, "_Check"))
t = Expr(:., :PyDateTimeAPI, QuoteNode(symbol(string(T, "Type"))))
f = Symbol(string("Py", T, "_Check"))
t = Expr(:., :PyDateTimeAPI, QuoteNode(Symbol(string(T, "Type"))))
@eval $f(o::PyObject) = pyisinstance(o, $t)
end

Expand Down
5 changes: 3 additions & 2 deletions src/pytype.jl
Expand Up @@ -261,7 +261,7 @@ type PyTypeObject
# Julia-specific fields, after the end of the Python structure:

# save the tp_name Julia string so that it is not garbage-collected
tp_name_save::ASCIIString
tp_name_save # This is a gc slot that is never read from

function PyTypeObject(name::AbstractString, basicsize::Integer, init::Function)
# figure out Py_TPFLAGS_DEFAULT, depending on Python version
Expand All @@ -280,7 +280,8 @@ type PyTypeObject
Py_TPFLAGS_HAVE_CLASS |
Py_TPFLAGS_HAVE_STACKLESS_EXTENSION |
Py_TPFLAGS_HAVE_INDEX)
name_save = bytestring(name)
# This and the `unsafe_convert` below emulate a `ccall`
name_save = Base.cconvert(Ptr{UInt8}, name)
Copy link
Member

@stevengj stevengj May 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be String(name). The name argument is an AbstractString, and could potentially be some other string type like UTF16String, and needs to be converted to UTF-8, which is what the bytestring call did.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the ccall interface. The code here is exactly the same as if you write ccall(..., (..., Ptr{UInt8}, ...,), ..., name, ...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you're talking about. CPython never looks at the tp_name_save field; this is is something I tacked on to the end of the struct so that the Julia-side object would cache a reference to the string to make sure it is not garbage collected for as long as I keep the Julia type object around (forever).

t = new(0,C_NULL,0,
unsafe_convert(Ptr{UInt8}, name_save),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be just pointer(name_save)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not if you want to support AbstractString.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name is an AbstractString. name_save = String(name) is a UTF-8 string.

convert(Int, basicsize), 0,
Expand Down
3 changes: 2 additions & 1 deletion test/runtests.jl
@@ -1,4 +1,5 @@
using Base.Test, PyCall, Compat
import Compat.String

PYTHONPATH=get(ENV,"PYTHONPATH","")
PYTHONHOME=get(ENV,"PYTHONHOME","")
Expand Down Expand Up @@ -132,7 +133,7 @@ end
# in Python 3, we need a specific encoding to write strings or bufferize them
# (http://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface)
pyutf8(s::PyObject) = pycall(s["encode"], PyObject, "utf-8")
pyutf8(s::ByteString) = pyutf8(PyObject(s))
pyutf8(s::String) = pyutf8(PyObject(s))

# IO (issue #107)
#@test roundtripeq(STDOUT) # No longer true since #250
Expand Down