4

I'm currently working on Sublime Text 3 Using Jedi - Python autocompletions and to be specific it works with most basic things. However I use it like in this case with BeautifulSoup4

The main issue, is, not displaying properly completions for when doing multiple dot (.) methods on a file and the completor has to rely on seeing it first like .find_all method then it will suggest it (however this seems to be the autocompletion from Sublime Text 3 itself).

What happens in the next case

import requests
from bs4 import BeautifulSoup as Soup // works ok, shows all suggestions

request = requests.get('http://example.com')    
soup = Soup(request.text, 'lxml')


main = soup.find('body') // shows find method 
//However, No available completions in the next case
second_lookup = main.find('div') // doesn't show any autocompletions/hints when starting w/ .fi..

Same goes when looking any other 'deeper' methods for autocompletions. I've tried so far tweaking all the settings in the Jedi..settings file. That didn't help and I've tried using Anaconda as it has some additional tools also including Jedi.

This seems to be specific to some libraries like numpy and bs4 for example.

Note:

This isn't specific to Sublime Text 3. Same thing goes for Atom and similar IDEs.

Yono
  • 2,176
  • 2
  • 10
  • 25
  • 2
    Does anything shows after you type `.` after `main` ? – Dinko Pehar Oct 28 '19 at 17:38
  • No, it doesn't show any completions. It was supposed to show class methods (from bs4) – Yono Oct 28 '19 at 22:13
  • 1
    I'll check on this more later – Dinko Pehar Oct 28 '19 at 23:40
  • Thanks, hopefully someone (like you) can clarify more the problem and get at least to what is the issue here. Like pinpoint, aham the Jedi core is doing this wrong. – Yono Oct 28 '19 at 23:58
  • The problem is basically that the code in `bs4.element.Tag._find_all` (which is what `Soup.find` does), is so hard to infer, that Jedi just doesn't understand it. When I'm reading the code, I'm not even quite sure what the return types can be. So how would Jedi understand... Anyway: The solution would be to give the find method an annotation to show what types it returns. It's currently just very unclear what gets returned there. – Dave Halter Nov 08 '19 at 12:08

1 Answers1

1

Python is a dynamic language. Arguments of a function or method rely completely on type specification by docstrings. Same goes for return type.

For example, this is docstring (or documentation) of a get function of requests module:

def get(url, params=None, **kwargs):
    r"""Sends a GET request.

    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary, list of tuples or bytes to send
        in the query string for the :class:`Request`.
    :param \*\*kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    kwargs.setdefault('allow_redirects', True)
    return request('get', url, params=params, **kwargs)

Return type is specified in function definition. You can also specify type of arguments for functions.

However, the find method of Soup class is written like this:

def find(self, name=None, attrs={}, recursive=True, text=None,
         **kwargs):
    """Return only the first child of this Tag matching the given
    criteria."""
    r = None
    l = self.find_all(name, attrs, recursive, text, 1, **kwargs)
    if l:
        r = l[0]
    return r

Editors can lookup find method of Soup class. But, they don't know what type of object this method returns.


Workaround is to specify type when assigning to variable:

import requests
from bs4 import Tag
from bs4 import BeautifulSoup as Soup

request = requests.get('http://example.com')

soup = Soup(request.text, 'lxml')

main: Tag  = soup.find('body')

# Auto completion works.
second_lookup = main.find('div')

Or you can add :rtype: Tag to find docstring. I know it returns Tag object since type(main) or type(second_lookup) both return <class 'bs4.element.Tag'>.

Links I provided are enough for you to learn about static typing in python and perfectly document your code. Hope this helps.

Dinko Pehar
  • 3,766
  • 3
  • 14
  • 34
  • 1
    Thank you this was a very useful insight. Hopefully we can work something out other than this solution as it isn't that convenient and would NOT work for a typical user. Therefore I would like to research a more convenient solution for the masses. I appreciate it quite a lot that you took your time to write this post and will accept it as a solution if no other answer appears. – Yono Oct 29 '19 at 15:14
  • 1
    No problem. I agree with you that answer is workaround. But that's the problem with dynamic languages, for example javascript (or some if it's library or framework). Because everything is dynamic. However, Typescript is really popular these days. And those type annotations go a long way for intellisense. – Dinko Pehar Oct 29 '19 at 16:38
  • Could we possibly put this :TAG in beautifulsoup library so that it works from there on? Then after suggest an commit and merge with them? – Yono Oct 30 '19 at 23:56
  • You can. But they are hosted on lunchpad. https://launchpad.net/beautifulsoup . You can maybe report a bug there ? – Dinko Pehar Oct 31 '19 at 04:58