Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.stack.imgur.com/5EGbk.jpg

like image 786
Romans Avatar asked Jan 12 '20 08:01

Romans


2 Answers

The simplest example would be:

.
├── functions
│   ├── functions.py
└── main
    └── main.py

Now in the functions/functions.py I have:

from datetime import datetime

def print_datetime():
    print(datetime.utcnow())

and in main/main.py I have:

import sys
sys.path.append(".")

from functions.functions import print_datetime

if __name__ == '__main__':
    print_datetime()

This sys.path.append(".") is helping you to switch the context from where you are calling the main.py, to be more accurate it adds higher directory to python modules path.

And while you are in the top-level directory of the project, you can now run the main.py which will produce a result like this:

(venv) user@pc: .../59702230 
$ python main/main.py 
2020-01-12 09:51:01.469436

For more details on how to do this, you can read a great QA in the beyond top level package error in relative import where is a lot of great information on how to solve the same issue with different approaches.

I hope that it will help you!

like image 83
simkusr Avatar answered Oct 22 '22 00:10

simkusr


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.

like image 37
Gino Mempin Avatar answered Oct 22 '22 00:10

Gino Mempin