0

I'm using Python 3.95, and have two files:

  • shapes.py, which defines class Circle, class Square, and class Triangle
  • textures.py, which defines class Smooth and class Rough

I'd like to be able to do something like:

from .shapes import *

but I get error ImportError: attempted relative import with no known parent package.

All files are stored in the same folder, and I'm trying to execute Python from that folder, on Python files stored in that folder.

There are numerous posts on SO describing this error, and I've tried their solutions, but to no avail. It seems like some of this depends on Python 2 vs 3, some depends on which folder you're executing from, some depends on packages and modules (which I do not entirely understand).

Some things I've tried which have not worked:

  • Creating an __init__.py file
  • Using from shapes import * instead of from .shapes import *
  • Using from .shapes import Circle
  • Adding these lines:
import sys
import os
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(SCRIPT_DIR))

This is likely a basic mistake: I'm not trying to build a module or package for distribution, I simply want to put different classes into different files, instead of all my classes in one giant file. How can I do so?

SRobertJames
  • 8,210
  • 14
  • 60
  • 107
  • 3
    What's the error when using `from shapes import *`? As this is the way to do this. – matszwecja Jan 31 '22 at 22:37
  • 1
    Does this answer your question? [How to do relative imports in Python?](https://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python) – TomServo Jan 31 '22 at 23:03
  • If you do a web search on the first three or four words of just about *any* python error message, you'll likely find a good answer on the first page, often here on Stackoverflow. – TomServo Jan 31 '22 at 23:05
  • @TomServo Yes, I checked all of those pages; the solutions posted didn't work, as my post shows. I could link to each page I tried and post the attempt to use it and the error message, but that would just confuse the core issue. – SRobertJames Feb 01 '22 at 00:38

3 Answers3

1

The current directory is only prepended to sys.path automatically if the script is the python file (not if the script is the first argument to python like python app.py).

I think that you can either:

  • add #! /usr/bin/env python at the start of the main file and make it executable with chmod +x main.py
  • append the right directoy to sys.path, as it seems to me that you are trying to append the parent dir. SCRIPT_DIR in your last attempt is already the current directory and you don't need to call dirname on it again.
rewritten
  • 16,280
  • 2
  • 47
  • 50
0

There's no need for a relative import if your main script needs to use a module in the same folder. If you have a main.py and a shapes.py (containing for example a function fun1()), just use any of these:

import shapes

shapes.fun1()


from shapes import fun1

fun1()


from shapes import *

fun1()

Note that the latter is not preferable, since it's not at all clear what you're importing and if shapes.py is later changed to include something that shadows something from an earlier import, it may break your code in surprising ways. Surprise is bad.

If you're writing a package called shapes, create a folder called shapes, put an __init__.py in it, and a Python file which could be called shapes.py or anything you want, as you'll be importing what's relevant from the __init__.py.

Then shapes/__init__.py could be something like:

from .shapes import *

Here, using the * makes a bit more sense, although I'd still favour from .shapes import fun1. The . is not needed, but here it makes sense, because it is relative to another file that's also in the package.

And shapes/shapes.py might be something like:

from .other_mod import fun2

def fun1():
    fun2()

Here, the . makes sense if shapes.py and other_mod.py are always going to be sitting next to each other in the package, but perhaps move around within the internal structure. Or perhaps you want to use the explicit . to avoid conflicts with other names.

If other_mod.py is something like:

def fun2():
    print('hello')

You could write a main.py in the same folder where the shapes folder sits and the code with shapes imports above would work.

Grismar
  • 27,561
  • 4
  • 31
  • 54
0

Can you try create new folder and add [shapes.py,textures.py,init.py] files into shapes folder

backend/
|
|------folder_shapes/shapes.py
|------folder_shapes/textures.py
|------folder_shapes/__init__.py
|------your_script.py
|

Then try import from your_script.py

ma9
  • 158
  • 11