rope icon indicating copy to clipboard operation
rope copied to clipboard

Problem of os.path

Open mcepl opened this issue 7 years ago • 2 comments

See https://groups.google.com/d/topic/rope-dev/08LAzaQ7pzQ/discussion and http://thread.gmane.org/gmane.comp.python.rope/59/. There are two simple test cases.

  1. In a file with the following text (| is where the cursor is):

    import os
    os.path.p|
    

    try to do code completion and there is none.

  2. Other one is on this file:

    import os.path
    
    filename = '/etc/passwd'
    
    print os.path.ex|
    

    try to complete on the os.path.ex (there is os.path.exists of course)

From the above linked discussion with @aligrudi , there seem to be these possible ways out (both in .ropeproject/config.py:

  1. Switch ignore_bad_imports to True
  2. Put extension_modules to ['os']

Both of them seem to be rather hackish, none of them is probably good enough reason to switch default value for everybody, both of them could have some unforseen side-effects, and we don’t have a facility to switch defaults per-user (i.e., something like ~/.config/rope/config.py which would provide default values for every project which doesn’t sets something different, or at least a default template from which new .ropeproject/config.py is created when it is created).

I think the only problem from these three we can address at this moment is the default configuration file (at least in the standard-template option).

Of course, other way would be to somehow hard-wire to Rope a notion that os.path (and possibly some other modules?) is an exception, and it should be treated as such. But I am not sure it is a good idea.

mcepl avatar Sep 27 '16 10:09 mcepl

Hey guys! That's an interesting issue. To be honest I couldn't find the real reason of the issue but according to the discussion with @aligrudi the cause of it is that there are some bad imports in os.py https://groups.google.com/d/msg/rope-dev/08LAzaQ7pzQ/lgPCDXZTkMgJ I thought about this problem. I believe we overcomplicated it in rope Please correct me but we can simplify the process of codeassisting at least, for instance, we have following code: import os os.path.ex

Let's breakdown it into simple logic: How would I do that without rope (actually, it's easy for installed packages) (Pdb) import os.path (Pdb) dir(os.path) ['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_joinrealpath', '_unicode', '_uvarprog', '_varprog', 'abspath', 'altsep', 'basename', 'commonprefix', 'curdir', 'defpath', 'devnull', 'dirname', 'exists', 'expanduser', 'expandvars', 'extsep', 'genericpath', 'getatime', 'getctime', 'getmtime', 'getsize', 'isabs', 'isdir', 'isfile', 'islink', 'ismount', 'join', 'lexists', 'normcase', 'normpath', 'os', 'pardir', 'pathsep', 'realpath', 'relpath', 'samefile', 'sameopenfile', 'samestat', 'sep', 'split', 'splitdrive', 'splitext', 'stat', 'supports_unicode_filenames', 'sys', 'walk', 'warnings'] (Pdb) 'exists' in dir(os.path) We may loop through dir(os.path) and assist user all names which starts with ex But in rope we treat everything as ast and trying to process it by rope evaluators. And that makes things crazy to debug, even small issue in the external packages could break our code assist. BUT, usually when we are working in some project, we are working under virtualenv, or system python which reflects the python version of our code we are working on currently. So, I propose to make one change: at least, for codeassist if statements starts with external dependencies and there's no such submodule or module in current project, then we can simply do, something similar to: mod = importlib.import_module('os.path') avail_names = [n for n in dir(mod) if not n.startswith['__']] code_assist_names = [name for name in avail_names if name.startswith('ex')] that's all. It would be great to add one more layer to our codeassist module which works different depending on external or internal code user is trying to use. About overhead on importing real modules (I see no overhead at the moment), actually we do it already, we evaluate the files from external libraries to suggest something, etc, so it would be almost the same but instead we will put all job on python, and no code infrastructure needed, for instance, we may execute corresponding ast chunks directly, instead of parsing it step by step and executing step by step... But of course I think we need to enable proposed behaviour only if project config corresponding flag would be set. (the name of flag could be 'use_simplified_version_of_parsing_ast_tree') ?

Is it a stupid idea ?

sergeyglazyrindev avatar Dec 23 '16 22:12 sergeyglazyrindev

Actually, I thought about parsing different chunks of ast tree by different methods, for example: if code is following: import os; os.path. we will check if os imported, if imported, check if it's some builtin or external dependency, collect whole subtree of ast tree (os.path subtree) back to string, execute it, that's it. but now we evaluate step by step each ast node... which is correct but maybe we can simplify it and btw, with my method we can ignore some stupid import errors because python itself does not have such issue, it handles some bad imports, loads all modules, whatever, don't know.

sergeyglazyrindev avatar Dec 23 '16 22:12 sergeyglazyrindev