How can I resolve a python3 ModuleNotFoundError in thonny when importing from a subfolder of my project folder - python-3.x

I began developing my python3 application in a single source file, called main.py, but then began to implement sub-windows as classes and moved each class into a separate source file in the Classes subdirectory. The application ran fine as a single source file, but now with all the imports, it is not able to run, due to missing module errors. I want to resolve these errors so that the application can run with the new project directory hierarchy, making it possible to create parallel projects that make use of my Classes library.
I expect my application to run without generating errors.
I'm getting the following message in thonny Assistant when I run main.py:
ModuleNotFoundError: No module named 'ToplevelWindow'
python_backend.py, line 314
However, when I run CalibrationWindow.py in thonny, it shows:
The code in CalibrationWindow.py looks good.
Also, when I run ToplevelWindow.py in thonny, it shows:
The code in ToplevelWindow.py looks good.
I'm using thonny 3.3.10 via ssh hosted by a Raspberry Pi running raspbian buster and python 3.7.3.
My project directory structure is as follows:
gui
\
__init.py__
main.py
Classes
\
__init__.py
CalibrationWindow.py
ToplevelWindow.py
I added the empty __init__.py files, created in nano, in order to try to get the imports working, but have not noticed any improvement.
The source file essential contents are as follows:
# File: main.py
from tkinter import *
import tkinter.ttk as ttk
from Classes.CalibrationWindow import CalibrationWindow
def OpenCalibrationWindow():
CalibrationWindow()
# File: ToplevelWindow.py
import tkinter as tk
class ToplevelWindow():
def __init__(self, title, geometry):
self.window = tk.Tk()
#...
if __name__ == 'main':
obj = ToplevelWindow('Test ToplevelWindow', '600x400')
# File: CalibrationWindow.py
from ToplevelWindow import ToplevelWindow
from tkinter import *
class CalibrationWindow(ToplevelWindow):
def __init__(self, windowTitle, windowGeometry):
super().__init__(windowTitle, windowGeometry)
#...
if __name__ == 'main':
obj = CalibrationWindow('Test CalibrationWindow', '600x400')
The error only seems to appear when a source file within the Classes folder imports from another source file within the Classes folder.
I don't know where to find sys.path or how to set that up, so I don't think I have set up the project correctly for all imports to work right, but it seems the first level of imports is working and it's only the last level where it is going wrong.

Related

Is it possible to iterate a qrc file? [duplicate]

I have this estructure on my application:
|-App
|
|-functions
|
|-ui
|--ui.py
|
|images
|
|main.py
i have a functions folder with some scripts and a ui folder with the PyQt generated code on the ui.py file.
and a main.py file that loads the ui.py to show the interface and ui.py loads some images from the "images" folder on the root.
if I execute my script directly on python (double clic on main.py file), the images wont show..
But if I use the terminal with "python main.py" the images show correctly.
The references on ui.py are like:
icon.addPixmap(QtGui.QPixmap(_fromUtf8("images/flags/MXN.png"))
Use the Qt Designer Resource System to create a resource file for the images.
Then use PyQt's pyrcc tool to convert the Qt resource file into a python module.
NB: The python resource module should go in the same directory as your ui files. So if you created the resource file App/resources.qrc in Qt Designer, you should then convert it like this:
pyrcc5 -o App/ui/resources_rc.py App/resources.qrc
The equivalent tool for PySide (Qt4) was pyside-rcc. For PySide2/PySide6, the Qt rcc tool itself has an option to produce python output:
rcc -g python -o App/ui/resources_rc.py App/resources.qrc
If you're not using Qt Designer, see the standalone example below. The following files all go together in the same root directory. If the image files are in a sub-directory, the qrc file must use relative paths (e.g. subdir/image.jpg). The resource_rc module is generated by executing the following command within the root directory:
pyrcc5 -o resource_rc.py resource.qrc
To make the resources accessible, you must import the generated module:
import resource_rc
The files within the resource are then accessed by prefixing ":/" to the path (e.g. ":/image.jpg" in the example below).
resource.qrc
<RCC>
<qresource>
<file>image.jpg</file>
</qresource>
</RCC>
main.py:
from PyQt5 import QtGui, QtWidgets
import resource_rc
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.label = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.label)
self.label.setPixmap(QtGui.QPixmap(':/image.jpg'))
app = QtWidgets.QApplication(['Test'])
window = Window()
window.show()
app.exec_()
UPDATE:
PyQt6 has now removed the pyrcc tool (see: How can resources be provided in PyQt6 (which has no pyrcc)?).

Python to EXE - PySide2 and Custom Modules

I'm trying to create an EXE from a Python project I built and I'm running into some issues. I've done this before with PyInstaller for simpler tools and cx-freeze for tools where I use custom modules but the way I used to set it up doesn't seem to be working anymore.
In this particular case I've tried:
cx-freeze==6.10
pyinstaller==4.10
py2exe==0.11.1.0
auto-py-to-exe==2.18.0
and a few others with no luck
Everything works perfectly fine through the Python 3.8 interpreter. I'm assuming it's either because of the way I'm importing PySide2 here (which I don't normally do but did for this project to see if it would speed up my programming time) or that the EXE modules can't find my custom modules. Here is a mock version of my program (names/paths changed for simplicity):
Example folder of my project ("C:\a\MyProjects\Project1"):
Example folder of the custom module I'm using. Each using various other built-in and/or 3rd party python modules. ("C:\a\path\to\external\modules"):
Example of my main file (C:\a\MyProjects\Project1\ui.py) I want to turn into an EXE:
import os
import sys
import colorsys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
import utils # module in project ("C:\a\MyProjects\Project1\utils.py")
sys.path.append(r"C:\a\path\to\external\modules") # custom module location for MyModule
from MyModule.foo import module1 as foo_mod1
from MyModule.foo import module2 as foo_mod2
from MyModule.bar import module1 as bar_mod1
from MyModule.bar import module2 as bar_mod2
from MyModule.baz import module1 as baz_mod1
from MyModule.baz import module2 as baz_mod2
class MainDialog(QDialog):
[...code...]
[...use of "dark.stylesheet"...]
[...use of "images\image 1.png"...]
[...use of "images\image 2.png"...]
def main():
global win
try: # try to close existing instances
win.close()
except NameError:
pass
win = MainDialog()
win.show()
if __name__ == "__main__":
app = QApplication.instance()
if not app:
app = QApplication(sys.argv)
main()
sys.exit(app.exec_())
Can someone tell me the best module and method to make this into a windowed (console-less), if possible, single file application. This is one of the more complicated tools I've had to make into a desktop app so if I can figure this out I should be good for most of the other things I have to do.
Thanks in advance.
EDIT:
Example of cx-freeze setup.py file in project I tried (C:\a\MyProjects\Project1\setup.py):
from cx_Freeze import setup, Executable
import sys
setup(
name="MyProject",
version="1.0",
options={'build_exe': {
'excludes': ["Tkinter"],
'includes': ["utils", "MyModule.foo", "MyModule.bar", "MyModule.baz"],
'path': sys.path + [r"C:\a\path\to\external\modules"],
'include_files': ["images\image 1.png", "images\image 2.png"],
'packages': ["PySide2.QtWidgets", "PySide2.QtCore", "PySide2.QtGui"]}},
executables=[Executable("ui.py", base="Win32GUI")]
Example of pyinstaller cmd command I tried:
cd C:\\a\MyProjects\Project1
pyinstaller -p "C:\a\path\to\external\modules" --onefile -w ui.py
# even tried this with a custom spec file like:
# pyinstaller --onefile -w ui.spec
There is a command in PyInstaller to include hidden modules call --hidden-module (You can use multile times). So, you can just do
pyinstaller -p "C:\a\path\to\external\modules" --onefile -w --hidden-module="example module 1" -hidden-module="example module 2" ui.py
This seems to have fixed itself after I got a new workstation and installed the latest Python (3.10) and Pyinstaller (5.1) versions.
Also think having your custom Python Libraries in the PYTHONPATH and/or PATH Environment variables may be important for allowing Pyinstaller to find them.

Cannot import a class from the same folder in python3

I have been trying all kinds of solutions from the site, but nothing seem to be working for me. My folder structure is:
python_tutorials
linked_list
__init__.py
linked_list.py
queue_using_linked_list.py
In my linked_list.py, I have a class called LinkedList. I am trying to inherit this class in my queue_using_linked_list.py class Queue. So in my queue_using_linked_list.py, I did:
from linked_list import linked_list
from linked_list.linked_list import LinkedList
from linked_list import LinkedList
All these gives me the error "ModuleNotFoundError: No module named 'linked_list'"
from .linked_list import LinkedList
Gives me the error "ImportError: attempted relative import with no known parent package"
I also tried moving the linked_list.py into a new package under linked_list, but still getting one of these error. In the pycharm IDE, all these show no errors, but when I execute they all fail. What am I missing?
The first two import lines are correct, but you have to start the Python interpreter from the python_tutorials directory, not from the linked_list directory.
If you then do import linked_list.queue_using_linked_list it will work as you intended.

using class from different directory

[Python 3.5.2, Docker container]
I have a class BCM in a file called metrics.py which I would like to use in several Jupyter notebooks which are in different directories. When they are in the same file, the following obviously works from metrics import BCM. I would like it to work with the following directory structure.
experiments\
common\
__init__.py
metrics.py
exp1\
glm.ipynb
exp2\
gbm.ipynb
It works if I do the following
import os, sys
module_path = os.path.abspath(os.path.join('..'))
if module_path not in sys.path:
sys.path.append(module_path)
from common.metrics import BCM
Based on posts that I have seen here, it would seem that the following should work from ..common.metrics import BCM. I get the following error SystemError: Parent module '' not loaded, cannot perform relative import.
Is there a way to use that class without changing the path as shown above?

Python 3.5 - Smart module imports in the file tree

I was wondering if it was possible for modules in a project to be smart about their imports...
Say I have the following data structure :
/parent-directory
/package
__init__.py
main.py
/modules
__init__.py
one.py
/submodules-one
__init__.py
oneone.py
onetwo.py
two.py
Files higher in the hierarchy are supposed to import Classes from those lower in the hierarchy.
For instance main.py has
import modules.one
import modules.two
Now I'd like to be able to directly run not only main.py, but also one.py (and all the others)
Except that it doesn't work like I hoped :
If I run from main.py, I need to have in one.py
import modules.submodules-one.oneone
import modules.submodules-one.onetwo
But if I run from one.py, I'll get an error, and I need to have instead
import submodules-one.oneone
import submodules-one.onetwo
I've found a hacky way to get around it using in one.py :
if __name__ == '__main__':
import submodules-one.oneone
import submodules-one.onetwo
else:
import modules.submodules-one.oneone
import modules.submodules-one.onetwo
But isn't there a better solution?
P.S.: I also have an additional complication, I'm using pint,
which to work properly only needs to have a single instance of the unit registry, so I have in the top ____init____.py :
from pint import UnitRegistry
ur = UnitRegistry()
And obviously
from .. import ur
will fail if running from one of the files of the subfolders.
Thank you in advance for your answer.

Resources