Create and use settings module in Python - python

I am new to Python so bear with me. I use the pyDev plugin fore eclipse. There are three files:
tool.py:
from gui import Tool_Window
import wx
import settings
if __name__ == '__main__':
window = wx.App()
Tool_Window(None, settings.WindowHeader)
window.MainLoop()
Tool_Window.py:
from Tool import settings
import wx
class Tool_Window(wx.Frame):
def __init__(self, parent, title):
super(Tool_Window,self).__init__(parent, title = title)
self.SetDimensions(settings.WindowOpenX,
settings.WindowOpenY,
settings.WindowWidth,
settings.WindowHeight)
settings.py:
WindowHeader = 'The SuperAwesome Tool'
WindowOpenX = 500
WindowOpenY = 100
WindowWidth = 200
WindowHeight = 400
The "tool.py" file is in a package called "Tool", as is the "settings.py" file, and "Tool_Window" is in the package "gui".
I am getting error messages from a previous file I had in the project, now renamed to the "settings.py". I have tried cleaning the project in Eclipse, but nothing happens. The error message looks like:
Traceback (most recent call last):
File "/home/oystein/workspaces/python/awesome.tool/src/Tool/tool.py", line 8, in <module>
Tool_Window(None, settings.WindowHeader)
File "/home/oystein/workspaces/python/awesome.tool/src/gui/__init__.py", line 12, in __init__
# ;-)
AttributeError: class GeneralParameters has no attribute 'WindowParameters'
Previously I had a class named GeneralParameters with a sub-class WindowParameters, as I wanted to access static variables for settings. I relaized Python couldn't do it like that and changed it to the "settings.py" file.
I run the program from "tool.py"
Can anyone see what's wrong here?

You are running stale byte-code, remove the .pyc files and rerun your code.
The traceback reads the source from the .py file but is built from the bytecode, and the fact that is shows that the error is on a line that only consists of a comment is a hint that things are no longer in sync.
Normally, Python will clean up the .pyc file when stale, but only if the .py modification time is newer.

Related

servable panel app ModuleNotFoundError on included local module

I'm having issues deploying my Panel app to be served up as HTML.
Following instructions at https://panel.holoviz.org/user_guide/Running_in_Webassembly.html, with script.py as
import panel as pn
from mymodule import MyObj
pn.extension('terminal', 'tabulator', sizing_mode="stretch_width")
gspec = pn.GridSpec(sizing_mode='stretch_width', max_height=100, ncols=3)
PI = MyObj()
gspec[0, 0:1] = PI.tabs
gspec[0, 2] = PI.view
pn.Column(
"Text Text Text"
, gspec
).servable()
and mymodule/__init__.py:
__version__ = '0.1.0'
from .my_obj import MyObj
and mymodule/my_obj.py:
from .param_classes import ClassA
from .param_classes import ClassB
# etc
from .compute_obj import ComputeObj
class MyObj(object):
# all the details of the panel build, calling in turn
# param classes detailed in another file, and also calling another module
# to handle all the computation behind the panel
panel serve script.py --autoreload works perfectly, but
$ panel convert script.py --to pyodide-worker --out pyodide
$ python3 -m http.server
does not work. I get a big display at http://localhost:8000/pyodide/script.html: ModuleNotFoundError: no module named 'mymodule', and an infinite loop spinning graphic, and in the Developer Tools Console output:
pyodide.asm.js:10 Uncaught (in promise) PythonError: Traceback (most recent call last):
File "/lib/python3.10/asyncio/futures.py", line 201, in result
raise self._exception
File "/lib/python3.10/asyncio/tasks.py", line 232, in __step
result = coro.send(None)
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 506, in eval_code_async
await CodeRunner(
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 359, in run_async
await coroutine
File "<exec>", line 11, in <module>
ModuleNotFoundError: No module named 'mymodule'
at new_error (pyodide.asm.js:10:218123)
at pyodide.asm.wasm:0xdef7c
at pyodide.asm.wasm:0xe37ae
at method_call_trampoline (pyodide.asm.js:10:218037)
at pyodide.asm.wasm:0x126317
at pyodide.asm.wasm:0x1f6f2e
at pyodide.asm.wasm:0x161a32
at pyodide.asm.wasm:0x126827
at pyodide.asm.wasm:0x126921
at pyodide.asm.wasm:0x1269c4
at pyodide.asm.wasm:0x1e0697
at pyodide.asm.wasm:0x1da6a5
at pyodide.asm.wasm:0x126a07
at pyodide.asm.wasm:0x1e248c
at pyodide.asm.wasm:0x1e00d9
at pyodide.asm.wasm:0x1da6a5
at pyodide.asm.wasm:0x126a07
at pyodide.asm.wasm:0xe347a
at Module.callPyObjectKwargs (pyodide.asm.js:10:119064)
at Module.callPyObject (pyodide.asm.js:10:119442)
at wrapper (pyodide.asm.js:10:183746)
I should add that I'm using poetry to manage packages and build the venv, and I'm operating all the above from within the activated .venv (via poetry shell)
I've tried all the tips and tricks around append the local path to sys.path. Looking at the .js file that the convert utility generates, I gather it would work if all the code were in one file, but forcing bad coding practice doesn't sound right.
I imagine there could be some kind of C++ build-style --include argument to panel convert, but there are no man pages, and the closest I can get with online documentation is --requirements ./mymodule, but no joy.
Could anybody please advise?

PyCharm & console don't let me use local modules

I'm absolutely frustraded about the fact that I can't start my Python journey. I have a simple service which I use as a training with Python which is new for me.
I've downloaded PyCharm and as long as I had one file, everything was fine.
That I decided to to some structure and suddenly my project stopped working.
I have a structure like:
project/
project/employees
project/employees/__init__.py
project/employees/employees.py
project/server.py
project/venv/
project/venv/(...)
The project is a source root.
And yet I have something like this:
Traceback (most recent call last):
File "C:/Users/user/PycharmProjects/project/server.py", line 5, in <module>
from employees.employees import Employees, EmployeesName
File "C:\Users\user\PycharmProjects\project\employees\employees.py", line 4, in <module>
from server import db_connect
File "C:\Users\user\PycharmProjects\project\server.py", line 5, in <module>
from employees.employees import Employees, EmployeesName
ImportError: cannot import name 'Employees'
I tested this with VS Code and CMD and the same happend.
I would be grateful for any suggestions!
EDIT:
employees.py:
from flask_jsonpify import jsonify
from flask_restful import Resource
from server import db_connect
class Employees(Resource):
(...)
class EmployeesName(Resource):
(...)
The problem here is that you have a circular dependency.
In employees.py you import server.py; and vice versa.
You have to rearrange your .py files in order that not to happen anymore.

How to store the results of a command to a variable?

I'm trying to build a context menu that will show a tree structure of all my packages and their resources. Something like this terrible MS Paint rendering I drew:
I have PackageResourceViewer installed. It offers commands that show in a window. But I would like to use them to populate these sub-context menues:
get_packages_list that I think will populate the first sub-menu (packages)
list_package_files that should populate each subsequent sub-menu
However, I'm not sure how to get the output of these into a context menu. I've been looking at python (writing a sublime plugin for this).
How do I get the output of these commands into a variable?
My Code
import sublime
import sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.view.insert(edit, 0, package_resource_viewer)
But it gives me this error:
>>> view.window().run_command("example")
Traceback (most recent call last):
File "C:\Program Files\Sublime Text 3\sublime_plugin.py", line 818, in run_
return self.run(edit)
File "C:\Users\heete\AppData\Roaming\Sublime Text 3\Packages\User\hello_world.py", line 7, in run
self.view.insert(edit, 0, package_resource_viewer)
NameError: global name 'package_resource_viewer' is not defined
Obviously I haven't gotten far, but I can't even get the output of this to show in the buffer.
You can import and access those commands. I made a minimal example, which prints the packages to the current view.
However output the to a context/sidebar menu seems to be harder, because they are usually static and you cannot just create one dynamically. (You may try to create a static menu file via a command.)
import sublime_plugin
from PackageResourceViewer.package_resources import (
get_packages_list, list_package_files
)
class ExampleListPackagesCommand(sublime_plugin.TextCommand):
def run(self, edit):
packages = get_packages_list()
insert_sb = []
insert_sb.append("Installed Packages:")
insert_sb.extend(packages)
for package in packages:
insert_sb.append("")
insert_sb.append(package)
package_files = list_package_files(package)
insert_sb.extend("\t" + pf for pf in package_files)
self.view.insert(edit, 0, "\n".join(insert_sb))

Importing a sub class from a sub folder

New to Python I'm trying to setup a simple OOP-structure of files, folders and classes. Here are the file paths:
C:\Users\Mc_Topaz\Programmering\Python\Terminal\Main.py
C:\Users\Mc_Topaz\Programmering\Python\Terminal\Connections\Connection.py
C:\Users\Mc_Topaz\Programmering\Python\Terminal\Connections\NoConnection.py
Notice Connection.py and NoConnection.py is loacted in sub folder Connections.
Connection.py
class Connection:
def __init__(self):
pass
def ToString(self):
pass
NoConnection.py
from Connection import Connection
class NoConnection(Connection):
def __init__(self):
pass
def ToString(self):
print("No connection")
In the Main.py file I would like to call the ToString() method from each class.
Main.py
from Connections.Connection import Connection
from Connections.NoConnection import NoConnection
connection = Connection()
print(connection.ToString())
noConnection = NoConnection()
print(noConnection.ToString())
When I run the Main.py file I get this error:
C:\Users\Mc_Topaz\Programmering\Python\Terminal>Main.py Traceback
(most recent call last): File
"C:\Users\Mc_Topaz\Programmering\Python\Terminal\Main.py", line 2, in
from Connections.NoConnection import NoConnection
File
"C:\Users\Mc_Topaz\Programmering\Python\Terminal\Connections\NoConnection.py",
line 1, in
from Connection import Connection
ImportError: No module named 'Connection'
It seems that the interpreter cannot import the NoConnection class in my Main.py file due to it cannot import the Connection class from the NoConnection.py file.
I can run Connection.py and NoConnection.py separately with no problems.
I don't understand why the Main.py don't run. I assume is something super simple and I cannot see it due to I'm to green to Python.
For python to recognize a directory is a module, or a collection of python files, that directory must contain a file named __init__.py. That file doesn't need to contain anything code whatsoever, though it can. If you add this file to your Connections directory, the interpreter should be able to import the contained files.
Just to add on to what mobiusklein mentioned: a common practice with __init__.py is to import the objects you use most frequently to avoid redundancy in your imports. In your example your Connections\__init__.py would likely contain:
import Connection
import NoConnection
Then your Main.py could use the following import statements successfully:
from Connections import Connection, NoConnection
I think it's down to relative imports in Python 3.
Change the import line in NoConnection to be explicit...
from Connections.Connection import Connection
and it works in Python3 (it works either way in Python2). Path to Terminal may have to be on you PYTHONPATH environment variable.
"Python 3 has disabled implicit relative imports altogether; imports are now always interpreted as absolute, meaning that in the above example import baz will always import the top-level module. You will have to use the explicit import syntax instead (from . import baz)." from here https://softwareengineering.stackexchange.com/questions/159503/whats-wrong-with-relative-imports-in-python
So when you import Connection from NoConnection it will be looking for it at the Terminal level, not at the Terminal/Connections level.
UPDTAE: Read comments for this post as it contain the solution.
Still don't get this to work. But I have made some changes:
Changed names of classes
> Class Connection = Foo inside Connection.py
> NoConnection = Bar inside NoConnection.py
This is ensure that the interpreter don't get confused if Connection is a module or a class.
Dropped ini.py file
I have dropped the Connections\__init_.py file as this don't seem to be necessary in Python version 3.4.2.
Files still run separately
I can run Connection.py and NoConnection.py separately. So they work.
Main.py
from Connections.NoConnection import Bar
noConnection = Bar()
print(noConnection.ToString())
When running Main.py I get the same error at line 1:
"Cannot find module 'Connection' in NoConnection.py at line 1".
The only logical reason I can see why this error happens is:
The interpreter looks for Connection.py inside my Terminal folder as Python was started from that folder. Even if it's importing the NoConnection.py file from the Connections folder where Connection.py is located.
Is this a bug?

Hiding implementation files in a package

I have a module called spellnum. It can be used as a command-line utility (it has the if __name__ == '__main__': block) or it can be imported like a standard Python module.
The module defines a class named Speller which looks like this:
class Speller(object):
def __init__(self, lang="en"):
module = __import__("spelling_" + lang)
# use module's contents...
As you can see, the class constructor loads other modules at runtime. Those modules (spelling_en.py, spelling_es.py, etc.) are located in the same directory as the spellnum.py itself.
Besides spellnum.py, there are other files with utility functions and classes. I'd like to hide those files since I don't want to expose them to the user and since it's a bad idea to pollute the Python's lib directory with random files. The only way to achieve this that I know of is to create a package.
I've come up with this layout for the project (inspired by this great tutorial):
spellnum/ # project root
spellnum/ # package root
__init__.py
spellnum.py
spelling_en.py
spelling_es.py
squash.py
# ... some other private files
test/
test_spellnum.py
example.py
The file __init__.py contains a single line:
from spellnum import Speller
Given this new layout, the code for dynamic module loading had to be changed:
class Speller(object):
def __init__(self, lang="en"):
spelling_mod = "spelling_" + lang
package = __import__("spellnum", fromlist=[spelling_mod])
module = getattr(package, spelling_mod)
# use module as usual
So, with this project layout a can do the following:
Successfully import spellnum inside example.py and use it like a simple module:
# an excerpt from the example.py file
import spellnum
speller = spellnum.Speller(es)
# ...
import spellnum in the tests and run those tests from the project root like this:
$ PYTHONPATH="`pwd`:$PYTHONPATH" python test/test_spellnum.py
The problem
I cannot execute spellnum.py directly with the new layout. When I try to, it shows the following error:
Traceback (most recent call last):
...
File "spellnum/spellnum.py", line 23, in __init__
module = getattr(package, spelling_mod)
AttributeError: 'module' object has no attribute 'spelling_en'
The question
What's the best way to organize all of the files required by my module to work so that users are able to use the module both from command line and from their Python code?
Thanks!
How about keeping spellnum.py?
spellnum.py
spelling/
__init__.py
en.py
es.py
Your problem is, that the package is called the same as the python-file you want to execute, thus importing
from spellnum import spellnum_en
will try to import from the file instead of the package. You could fiddle around with relative imports, but I don't know how to make them work with __import__, so I'd suggest the following:
def __init__(self, lang="en"):
mod = "spellnum_" + lang
module = None
if __name__ == '__main__':
module = __import__(mod)
else:
package = getattr(__import__("spellnum", fromlist=[mod]), mod)

Categories