@@ -308,6 +308,71 @@ defmodule Livebook.Intellisense.PythonTest do
308308 )
309309 end
310310
311+ test "callables with name" do
312+ # NumPy functions are not regular functions, but they are callable,
313+ # so we want to treat those as functions.
314+
315+ context =
316+ intellisense_context_from_eval do
317+ import Pythonx
318+
319+ ~PY"""
320+ class GoodCallable:
321+ def __init__(self):
322+ self.__name__ = "good_callable"
323+ self.__doc__ = "This is a good callable."
324+
325+ def __call__(self, number):
326+ return number * 2
327+
328+ callable_good = GoodCallable()
329+
330+ class BadCallable:
331+ def __init__(self):
332+ self.__doc__ = "This is a bad callable."
333+
334+ # This is going to be invoked when accessing __name__, but it
335+ # can return anything, and we should not consider this callable
336+ # a function.
337+ def __getattr__(self, attr):
338+ return None
339+
340+ def __call__(self, number):
341+ return number * 2
342+
343+ callable_bad = BadCallable()
344+ """
345+ end
346+
347+ assert % {
348+ items: [
349+ % {
350+ label: "callable_bad" ,
351+ kind: :variable ,
352+ documentation: "(variable)" ,
353+ insert_text: "callable_bad"
354+ } ,
355+ % {
356+ label: "callable_good" ,
357+ kind: :function ,
358+ documentation: """
359+ This is a good callable.
360+
361+ ```
362+ good_callable(number)
363+ ```\
364+ """ ,
365+ insert_text: "callable_good(${})"
366+ }
367+ ]
368+ } =
369+ Intellisense.Python . handle_request (
370+ { :completion , "callable_" } ,
371+ context ,
372+ node ( )
373+ )
374+ end
375+
311376 test "class" do
312377 context =
313378 intellisense_context_from_eval do
0 commit comments