Search code examples
python-3.xvisual-studio-codepylint

How to correctly import a Python module in VS Code?


I've recently started programming in Python and I've decided to code some Delphi functions in Python. I've decided to create a single Python module that holds my functions.

Now, I tried to import it, but I get this error in Visual Studio Code:

unable to import 'functions' pylint(import error) [5, 1]

Here is my code:

import sys

sys.path.append('/Users/user123/Desktop/Python/Functions/')

import functions

Here is an image:

https://i.sstatic.net/5EGbk.jpg


Solution

  • Given your file/folder structure:

    ├── Functions
    │   └── functions.py
    ├── <main app folder>
    │   └── app.py
    

    Although your imports may run correctly once you've added path/to/Functions to sys.path, Pylint is giving you that warning because that is not the recommended way of declaring imports, especially when you're importing modules outside the app package/folder.

    From the PEP8 Style Guide for Imports:

    Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages) if the import system is incorrectly configured (such as when a directory inside a package ends up on sys.path):

    import mypkg.sibling 
    from mypkg import sibling 
    from mypkg.sibling import example
    

    The recommended solution is to setup Functions as a package by adding a __init__.py file under it:

    ├── parent
    │   └── Functions
    │       ├── __init__.py
    │       └── functions.py
    

    then importing your functions like one of these:

    sys.path.append("/path/to/parent")
    
    # option 1
    from Functions import functions
    functions.copy()
    functions.delete()
    
    # option2
    from Functions.functions import copy, delete
    copy()
    delete()
    

    Both options should run correctly and satisfy PyLint.

    Now, if you really want to do a non-absolute import like from functions import func, and get PyLint to accept that, I recommend renaming functions.py to something else. This is because, on some case-insensitive systems, importing Functions and functions could get treated as the same module. When you tell PyLint to look into /path/to/Functions (I'll show later), it might not be able to differentiate if copy and delete is part of Functions or of functions, and it might still show an import-error.

    So, what you need to do is rename functions.py (ex. filefuncs.py):

    ├── Functions
    │   └── filefuncs.py
    ├── <main app folder>
    │   └── app.py
    

    Then in you VS Code workspace, add this to your .vscode/settings.json file to tell PyLint where to look for the filefuncs module:

    "python.linting.pylintArgs": [
        "--init-hook",
        "import sys; sys.path.append('/path/to/Functions')"
    ]
    

    Then you can now import it same as your original code but without PyLint errors:

    sys.path.append("/path/to/Functions")
    from filefuncs import copy, delete
    copy()
    delete()
    

    The second way will get you what you need, but it contains some workarounds for PyLint to work. If you can use the recommended way I explained at the start, use that instead.