@@ -140,103 +140,49 @@ end
140140pyconvert_is_special_tname(tname:: String ) =
141141 tname in (" <arraystruct>" , " <arrayinterface>" , " <array>" , " <buffer>" )
142142
143- function _pyconvert_get_rules(pytype:: Py )
144- pyisin(x, ys) = any(pyis(x, y) for y in ys)
145-
146- # get the MROs of all base types we are considering
147- omro = collect(pytype. __mro__)
148- basetypes = Py[pytype]
149- basemros = Vector{Py}[omro]
150- for xtype in PYCONVERT_EXTRATYPES
151- # find the topmost supertype of
152- xbase = PyNULL
153- for base in omro
154- if pyissubclass(base, xtype)
155- xbase = base
156- end
143+ function _pyconvert_collect_supertypes(pytype:: Py )
144+ seen = Set{C. PyPtr}()
145+ queue = Py[pytype]
146+ types = Py[]
147+ while ! isempty(queue)
148+ t = pop!(queue)
149+ ptr = C. PyPtr(t)
150+ ptr ∈ seen && continue
151+ push!(seen, ptr)
152+ push!(types, t)
153+ if pyhasattr(t, " __bases__" )
154+ append!(queue, (Py(b) for b in t. __bases__))
157155 end
158- if ! pyisnull(xbase)
159- push!(basetypes, xtype)
160- xmro = collect(xtype. __mro__)
161- pyisin(xbase, xmro) || pushfirst!(xmro, xbase)
162- push!(basemros, xmro)
163- end
164- end
165- for xbase in basetypes[2 : end ]
166- push!(basemros, [xbase])
167156 end
157+ return types
158+ end
168159
169- # merge the MROs
170- # this is a port of the merge() function at the bottom of:
171- # https://www.python.org/download/releases/2.3/mro/
172- mro = Py[]
173- while ! isempty(basemros)
174- # find the first head not contained in any tail
175- ok = false
176- b = PyNULL
177- for bmro in basemros
178- b = bmro[1 ]
179- if all(bmro -> ! pyisin(b, bmro[2 : end ]), basemros)
180- ok = true
181- break
182- end
183- end
184- ok || error(
185- " Fatal inheritance error: could not merge MROs (mro=$mro , basemros=$basemros )" ,
186- )
187- # add it to the list
188- push!(mro, b)
189- # remove it from consideration
190- for bmro in basemros
191- filter!(t -> ! pyis(t, b), bmro)
192- end
193- # remove empty lists
194- filter!(x -> ! isempty(x), basemros)
195- end
196- # check the original MRO is preserved
197- omro_ = filter(t -> pyisin(t, omro), mro)
198- @assert length(omro) == length(omro_)
199- @assert all(pyis(x, y) for (x, y) in zip(omro, omro_))
200-
201- # get the names of the types in the MRO of pytype
202- xmro = [String[pyconvert_typename(t)] for t in mro]
203-
204- # add special names corresponding to certain interfaces
205- # these get inserted just above the topmost type satisfying the interface
206- for (t, x) in reverse(collect(zip(mro, xmro)))
207- if pyhasattr(t, " __array_struct__" )
208- push!(x, " <arraystruct>" )
209- break
210- end
211- end
212- for (t, x) in reverse(collect(zip(mro, xmro)))
213- if pyhasattr(t, " __array_interface__" )
214- push!(x, " <arrayinterface>" )
215- break
216- end
217- end
218- for (t, x) in reverse(collect(zip(mro, xmro)))
219- if pyhasattr(t, " __array__" )
220- push!(x, " <array>" )
221- break
222- end
223- end
224- for (t, x) in reverse(collect(zip(mro, xmro)))
225- if C. PyType_CheckBuffer(t)
226- push!(x, " <buffer>" )
227- break
228- end
160+ function _pyconvert_get_rules(pytype:: Py )
161+ typemap = Dict{String,Py}()
162+ tnames = Set{String}()
163+
164+ function add_type!(t:: Py )
165+ tname = pyconvert_typename(t)
166+ haskey(typemap, tname) || (typemap[tname] = t)
167+ push!(tnames, tname)
168+ return nothing
229169 end
230170
231- # flatten to get the MRO as a list of strings
232- mro_strings = String[x for xs in xmro for x in xs]
171+ for t in _pyconvert_collect_supertypes(pytype)
172+ add_type!(t)
173+ pyhasattr(t, " __array_struct__" ) && push!(tnames, " <arraystruct>" )
174+ pyhasattr(t, " __array_interface__" ) && push!(tnames, " <arrayinterface>" )
175+ pyhasattr(t, " __array__" ) && push!(tnames, " <array>" )
176+ (C. PyType_CheckBuffer(t) != 0 ) && push!(tnames, " <buffer>" )
177+ end
233178
234- typemap = Dict{String,Py}()
235- for t in mro
236- typemap[pyconvert_typename(t)] = t
179+ for xtype in PYCONVERT_EXTRATYPES
180+ pyissubclass(pytype, xtype) || continue
181+ for t in _pyconvert_collect_supertypes(xtype)
182+ add_type!(t)
183+ end
237184 end
238185
239- # get corresponding rules
240186 rules = PyConvertRuleInfo[
241187 PyConvertRuleInfo(
242188 tname,
@@ -245,10 +191,9 @@ function _pyconvert_get_rules(pytype::Py)
245191 rule. scope,
246192 rule. func,
247193 rule. order,
248- ) for tname in mro_strings for rule in get!(Vector{PyConvertRule}, PYCONVERT_RULES, tname)
194+ ) for tname in tnames for rule in get!(Vector{PyConvertRule}, PYCONVERT_RULES, tname)
249195 ]
250196
251- @debug " pyconvert" pytype mro = join(mro_strings, " " )
252197 return rules, typemap
253198end
254199
0 commit comments