Maya - How to create python scripts with more than one file? - python

It's my first post here, please understand that I'm a beginner and that I'm learning "on-the-job".
Can someone explain how can I import files from a different module in a Maya python script? I'm getting the following error:
Error: ImportError: file E:/.../bin/mainScript.py line 17: No module named tools
Here are my directories and codes:
Main_folder\
|-- install.mel
|-- ReadMeFirst.txt
`-- bin\
|-- __init__.py
|-- mainScript.py
|-- tools.py
`-- presets\
|-- bipedPreset.txt
|-- quadrupedPreset.txt
`-- [...] .txt
I'm trying to import tools.py in mainScript.py
EDIT:
Ok, as it won't fit in a comment I edit this post to add precisions. I moved the 'Main_folder' on my Desktop and ran the script once again in Maya. It still doesn't work but I have a more complete error traceback. Here it is:
# Error: Error in maya.utils._guiExceptHook:
# File "C:\Program Files\Autodesk\Maya2014\Python\lib\site-packages\maya\utils.py", line 332, in formatGuiException
# result = u'%s: file %s line %s: %s' % (exceptionType.__name__, file, line, exceptionMsg)
# UnicodeDecodeError: 'ascii' codec can't decode byte 0xfc in position 11: ordinal not in range(128)
#
# Original exception was:
# Traceback (most recent call last):
# File "<maya console>", line 3, in <module>
# File "C:/Users/UKDP/Desktop/Main_folder/bin/mainScript.py", line 17, in <module>
# from tools import ClassTest
# ImportError: No module named tools #

You need to make sure any importable modules are on you python path.
If your files are in E:/main_folder you'll need to do
import sys
sys.path.append("E:/main_folder")
import bin.tools
import bin.mainScript
and so on. The way you have it set up (with 'bin/__init__.py') you're telling python that the module is named bin and it has submodules named 'mainScript' and 'tools'. Long discussion here

Try importing like:
>>>import san.libs.stringops
Where the san is dir(in san create __init__.py)
libs is a dir(in libs create __init__.py)
and stringops.py is imported

Try this
I have a folder that is on my desktop and the folder is called Combo and has a script called combo.py and here is how I access it:
import sys #imports system's directory module
sys.path.insert(0,"C:/Users/dharmin.doshi/Desktop") #Add your directory, do not add your folder in the path unless the script is inside of folder inside of folder. Path needs to be in quotes and 0 is added as needed by the argument.
from Combo(Folder name) import combo (my python script)
reload (combo) #Optional to reload it every time you make changes to the script.
combo.run() #Call the function that runs the code.
In your case if you need to access tools.py then your path will be like:
sys.path.insert(0, "MainFolder/bin")
import tools
Hope this helps :)

exe1.py
import san.libs.stringops
import san.libs.maths
import san.libs.utils.ran
import san.printing
newstr = san.libs.stringops.add2string("hey","hi")
san.printing.myprint(newstr)
result = san.libs.maths.add(2,3)
san.printing.myprint(result)
random_number = san.libs.utils.ran.getnumber()
san.printing.myprint(random_number)

Related

Python Package Correct Import Structure For Source And Binaries?

I want to start by saying I know this has been answered many times before, but there was a lot of conflicting answers and half-solutions
Summary of layout
EDIT: GitHub Link Here
I am making a program valled ROSA in Python, and wish for it to be usable both by directly running a single script and by importing the code so that a user can write their own wrapper for it. Consequently, I have split the program into 2 files (well actually 3, but)
the file ROSA.py which contains a class called ROSA_ and uses class attributes from the foreign_potato_master.py file. Running this file directly does nothing
the file main.py which is imports ROSA.py and uses the ROSA_ class (it also uses variables from ROSA.py to decide whether the script is on a Raspberry Pi or a desktop, etc). This file is made to be run directly, and basically just calls the functions from ROSA_
the file foreign_potato_master.py which contains a few classes that contain dictionaries of strings that are used by ROSA.py to reply to the user. I moved these into a separate file to make it easier for others to edit the output of my program
Brief file contents:
ROSA.py:
import speech_recognition as sr
import foreign_potato_master
try:
import RPi.GPIO as GPIO # type: ignore
is_on_RPi = True
except ImportError:
# note: Probably a more elegant solution somewhere
# note: but this is what works for me atm
is_on_RPi = False
class ROSA_:
def __init__(self, json_path = None):
...
self.title = foreign_potato_master.Text_Decorations.title
self.symbols = foreign_potato_master.Text_Decorations.symbols
self.activations = foreign_potato_master.Responses.activations
self.keys = foreign_potato_master.Responses.keys
self.responses = foreign_potato_master.Responses.responses
self.prev_responses = foreign_potato_master.Responses.prev_responses
...
def background_listening(self):
...
foreign_potato_master.py:
class Responses:
activations = [...]
keys = {...}
responses = {...}
prev_responses = {...}
class Text_Decorations:
title = '...'
symbols = {...}
...
main.py:
import ROSA
def main():
...
obj = ROSA.ROSA_()
speech = obj.background_listening()
...
if __name__ == '__main__': main()
init.py:
from ROSA import ROSA
from ROSA import foreign_potato_master
all of the files have some comments/docstrings/verison tags etc in the top, including the __init__.py
Directory Structure
ROSA
|- bin
|- ...
|- docs
|- ...
|- src
|- ROSA
|- __init__.py
|- foreign_potato_master.py
|- gpio.json
|- main.py
|- ROSA.py
My question:
What is the best way to import these files into each other?
# main.py
from . import ROSA
import .ROSA
Both of the above fail (ImportError: attempted relative import with no known parent package and SyntaxError: invalid syntax respectively)
# main.py
import ROSA
The above works when running as Python files, but not as compiled binaries (via pyinstaller):
Traceback (most recent call last):
File "\\192.168.0.8\source\projects\ROSA\src\ROSA\main.py", line 39, in <module>
File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
File "ROSA\__init__.py", line 35, in <module>
File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
File "ROSA\ROSA.py", line 80, in <module>
ModuleNotFoundError: No module named 'foreign_potato_master'
[2520] Failed to execute script 'main' due to unhandled exception!
the above was run in Windows Sandbox
EDIT: probably should have clarified, the exe was built using the following batch script:
:: \ROSA
pyinstaller --noconfirm --log-level=WARN --clean ^
--distpath ".\bin\bin" --workpath ".\bin\build" ^
--name ROSA --onefile ^
--paths ".\rosa-env\Lib\site-packages" ^
--hidden-import pyi_splash ^
--add-binary ".\src\ROSA\responses;.\responses" ^
--splash ".\docs\ico\hotpot-ai.png" --icon ".\docs\ico\hotpot-ai.ico" ^
.\src\ROSA\main.py
Finally (TL;DR):
So how can I import these files and have it work when run directly, when imported and when compiled to binary?

ModuleNotFoundError: No module named 'sharedFunctions'

I have a Python project in which I have the following folder structure:
> root
> download_module
> __init__.py
> downloadProcess.py
> sharedFunctions.py
> someHelper.py
> useSharedFunction.py
The download_module/__init__.py has the following code:
from .sharedFunctions import stringArgumentToDate
from .downloadProcess import downloadProcessMethod
The sharedFunctions.py file contains the following function:
def stringArgumentToDate(arg):
dateformat = "%m/%d/%Y"
date = None
if arg.isnumeric():
date = datetime.fromtimestamp(int(arg))
if date == None:
date = datetime.strptime(arg, dateformat)
return date
Then on the useSharedFunction.py I try to import the shared function and use it like this.
from download_module import stringArgumentToDate
from download_module import downloadProcessMethod
def main():
arg = '03/14/2022'
dateArg = stringArgumentToDate(arg)
if __name__ == '__main__':
main()
When I try to run this by using python3 useSharedFunction.py I got the following error:
Traceback (most recent call last):
File "useSharedFunction.py", line 4, in <module>
from download_module import stringArgumentToDate
File "/Users/jacobo/Documents/project/download_module/__init__.py", line 2, in <module>
from .download_module import downloadAndProcessMethod
File "/Users/jacobo/Documents/project/download_module/downloadProcess.py", line 10, in <module>
from sharedFunctions import stringArgumentToDate, otherFunction
ModuleNotFoundError: No module named 'sharedFunctions'
I do believe the error is in downloadProcess since at the beggining of the file we got this import:
from sharedFunctions import stringArgumentToDate, otherFunction
from someHelper import Helper
Which refers to sibling files.
However I'm unsure what will be a proper fix to allow to run the downloadProcess.py main independently but also, being able to call it one of its method from a root or any other file out of the module.
Consider this structure:
┬ module
| ├ __init__.py
| ├ importing_submodule.py
| └ some_submodule.py
├ __main__.py
├ some_submodule.py
└ module_in_parent_dir.py
with content:
__main__.py
import module
/module/__init__.py
from . import importing_submodule
/module/importing_submodule.py
from some_submodule import SomeClass
/module/some_submodule.py
print("you imported from module")
class SomeClass:
pass
/some_submodule.py
print("you imported from root")
class SomeClass:
pass
/module_in_parent_dir.py
class SomeOtherClass:
pass
How sibling import works
(skip this section if you know already)
Now lets run __main__.py and it will say "you imported from root".
But if we change code a bit..
/module/importing_submodule.py
from module.some_submodule import SomeClass
It now says "You imported from module" as we wanted, probably with scary red line in IDE saying "Unresolved reference" if you didn't config working directory in IDE.
How this happen is simple: script root(Current working directory) is decided by main script(first script that's running), and python uses namespaces.
Python's import system uses 2 import method, and for convenience let's call it absolute import and relative import.
Absolute import: Import from dir listed in sys.path and current working directory
Relative import: Import relative to the very script that called import
And what decide the behavior is whether we use . at start of module name or not.
Since we imported by from some_submodule without preceeding dot, python take it as 'Absolute import'(the term we decided earlier).
And then when we also specified module name like from module.some_submodule python looks for module in path list or in current working directory.
Of course, this is never a good idea; script root can change via calls like os.chdir() then submodules inside module folder may get lost.
Therefore, the best practices for sibling import is using relative import inside module folder.
/module/importing_submodule.py
from .some_submodule import SomeClass
Making script that work in both way
To make submodule import it's siblings when running as main script, yet still work as submodule when imported by other script, then use try - except and look for ImportError.
For importing_submodule.py as an example:
/module/importing_submodule.py
try:
from .some_submodule import SomeClass
except ImportError:
# attempted relative import with no known parent package
# because this is running as main script, there's no parent package.
from some_submodule import SomeClass
Importing modules from parent directory is a bit more tricky.
Since submodule is now main script, relative import to parent level directory doesn't work.
So we need to add the parent directory to sys.path, when the script is running as main script.
/module/importing_submodule.py
try:
from .some_submodule import SomeClass
except ImportError:
# attempted relative import with no known parent package
# because this is running as main script, there's no parent package.
from some_submodule import SomeClass
# now since we don't have parent package, we just append the path.
from sys import path
import pathlib
path.append(pathlib.Path(__file__).parent.parent.as_posix())
print("Importing module_in_parent_dir from sys.path")
else:
print("Importing module_in_parent_dir from working directory")
# Now either case we have parent directory of `module_in_parent_dir`
# in working dir or path, we can import it
# might need to suppress false IDE warning this case.
# noinspection PyUnresolvedReferences
from module_in_parent_dir import SomeOtherClass
Output:
"C:\Program Files\Python310\python.exe" .../module/importing_module.py
you imported from module
Importing module_in_parent_dir from sys.path
Process finished with exit code 0
"C:\Program Files\Python310\python.exe" .../__main__.py
you imported from module
Importing module_in_parent_dir from working directory
Process finished with exit code 0

ModuleNotFoundError: No module named 'createCredentialsXML'

I have a question about my new python project. It is the first time that I use different folders for my project.
I have the following structure:
project
src
securityFunc
__init__.py
createCredentialsXML.py
main.py
I work in PyCharm environment.
After pressing Play i get the error message:
Traceback (most recent call last):
File "C:\project\src\main.py", line 1, in <module>
from securityFunc import *
File "C:\project\src\securityFunc\__init__.py", line 1, in <module>
from createCredentialsXML import *
ModuleNotFoundError: No module named 'createCredentialsXML'
My main function looks like this:
from securityFunc import *
if __name__ == '__main__':
generate_key()
__init__.py:
from createCredentialsXML import *
createCredentialsXML.py:
def generate_key():
key = base64.urlsafe_b64encode(os.urandom(2048))
with open("../key/secret.key", "wb") as key_file:
key_file.write(key)
I tried using Path or sys.path to fix the problem. But it does not work.
Can you please tell me how to fix the problem?
Since you're doing a relative import, you need to add a . before your module name:
from .createCredentialsXML import *
The dot means the module is found in the same directory as the code importing the code.
You can read more about it here
createCredentialsXML.py works in the module securityFunc; you must specify the scope of the import. Using
from securityFunc.createCredentialsXML import *
in securityFunc.__init__.py should work.

Simple case of __init__.py and import giving mysterious module not found

I've tried this from so many different angles but can't sort it out. Must be such a simple case. In Python 3.7.6:
Directory structure:
./modtest/
./modtest/__init__.py
./modtest/test1.py
./modtest/test2.py
test1.py:
import modtest
def x(i):
print(i)
y(i)
test2.py:
def y(i):
print(i)
__init__.py is an empty file.
When I attempt to run the code:
$ /Users/pitosalas/miniconda3/bin/python /Users/pitosalas/mydev/rsb_py/modtest/test1.py
Traceback (most recent call last):
File "/Users/pitosalas/mydev/rsb_py/modtest/test1.py", line 1, in <module>
import modtest
ModuleNotFoundError: No module named 'modtest
From what I read this should've worked. I'm sure there's something trivial wrong!
You are importing modtest in test1.py while this module itself resides inside of modtest. This can't be because modest wouldn't have yet been defined and added to the search path. So this is what you should have actually:
./modtest/
./modtest/__init__.py
./modtest/
./modtest/test2.py
./test1.py # this module must be outside of modtest

A strange "No module named 'XX' " problem

I know how to import a package or module, but I meet a quite strange problem.
If I run swmm5_extend_function/example.py, everything is fine. However, when I run example.py, errors occur:
Traceback (most recent call last):
File "example.py", line 2, in <module>
from swmm5_extend_function.Swmm5Extend import SWMM5ReadInp
File "C:\project\swmm5_extend_function\Swmm5Extend.py", line 1, in <module>
import swig.SWMM5ReadInpFile as swmm
ModuleNotFoundError: No module named 'swig'
Here is my project structure:
project/
-- example.py
-- ......
-- swmm5_extend_function/
-- __init__.py
-- example.py
-- Swmm5Extend.py
-- swig/
-- __init__.py
-- SWMM5ReadInpFile.py
-- ....
Here is code of each .py file:
swmm5_extend_function/Swmm5Extend.py
import swig.SWMM5ReadInpFile as swmm
class SWMM5ReadInp(object):
pass
swmm5_extend_function/example.py
from Swmm5Extend import SWMM5ReadInp
example.py
from swmm5_extend_function.Swmm5Extend import SWMM5ReadInp
I want to know why this strange error happens.
For a better explanation, I've created the following folder structure:
test/
-- __init__.py
-- greeter.py # Greets in German
-- subfolder/
-- __init__.py
-- greeter.py # Greets in Italian
-- test.py
-- deepfolder/
-- __init__.py
-- greeter.py # Greets in France
As you may notice, we have 3 files with the same name, each one greets in a different language using a function with the same name. The only function in a greeter.py file is:
def says():
print("Hello World!")
IMPORT FROM THE SAME FOLDER
If from test.py file we import greeter and run the says function, we'll have:
import greeter as greeter
greeter.says()
Output:
Buongiorno Mondo! # Italian output
IMPORT FROM A SUBFOLDER
But what if we want to import from a subfolder?
To import from a subfolder (i.e., deepfolder/), we simply add an empty __init__.py file into the folder, then we can specify the path in the import:
import deepfolder.greeter as greeter
greeter.says()
Output:
Bonjour le Monde! # France output
IMPORT FROM A PARENT FOLDER
At last, you may want to import from a parent folder.
You should try to have your main running file at the top of the folder tree, but things happens and you find yourself looking to import a module from a parent folder.
For doing this, you need to add the parent folder to the sys.path:
import sys
sys.path.append("/path/to/dir")
from test import greeter as greeter
greeter.says()
Output:
Guten Morgen Welt! # German output
Importing scripts and modules isn't really the most pythonic way to solve things, you may want to have a look on Python's documentation about packages.
TL;DR
In your project/example.py use
import swmm5_extend_function.swig.SWMM5ReadInpFile as swmm
instead of
import swig.SWMM5ReadInpFile as swmm

Categories

Resources