maya python call function from another py file - python

I have a python script saved to file.
test1.py
import maya.cmds as cmds
import sys
def process():
print 'working'
I need to run the function from this script inside another python script, inside maya. I have:
import sys
sys.path.append('J:\scripts\src\maya')
from test1 import process
test1.process()
but it gives me:
from test1 import process
# Error: ImportError: file <maya console> line 4: cannot import name process #
What am I doing wrong here?
('import test1' gives no error, so the path is correct).

Solution:
Reload your test1 module, my guess is that you created and imported test1 without the process method inside. To effectively reload a module, you can't just re-import it, you have to use the reload.
reload(test1)
from test1 import process
Other observations:
Use raw string when using paths:
Add r before your path string:
sys.path.append(r'J:\scripts\src\maya')
Python Doc
The backslash () character is used to escape characters that
otherwise have a special meaning, such as newline, backslash itself,
or the quote character. String literals may optionally be prefixed
with a letter 'r' or 'R'; such strings are called raw strings and use
different rules for interpreting backslash escape sequences.
Check the way you import your modules:
You wrote, which is not valid:
from test1 import process
test1.process()
But you can have either way:
import test1
test1.process()
or:
from test1 import process
process()
To sum-up these are the ways to import a module or package:
>>> import test_imports
>>> from test_imports import top_package
>>> from test_imports import top_module
test_imports.top_module
>>> from test_imports.top_package import sub_module
test_imports.top_package.sub_module
assuming you have the following hierarchy:
J:\scripts\src\maya # <-- you are here
.
`-- test_imports
|-- __init__.py
|-- top_package
| |-- __init__.py
| |-- sub_package
| | |-- __init__.py
| | `-- other_module.py
| |-- sub_module.py
`-- top_module.py
Credits goes to Sam & Max blog (French)

First you need to add the script location path in system path.
and if you are making this as a python package than do not forget to add
a __init__.py file in the package directory.
Than you can execute following code.
import sys
path = r'J:\scripts\src\maya'
if path not in sys.path:
sys.path.append(path)
import test1
test1.process()

Related

ModuleNotFoundError when using Mock

I'm fairly new to Python. I'm working on a small Python project, structured as so:
artwork_grabber/
|
|-- artwork_grabber/
| |-- __init__.py
| |-- helpers.py
|
|-- tests/
| |-- __init__.py
| |-- test_module.py
|
|-- README
Both __init__.py files are empty of any content.
The helpers.py file contains a few functions, one of which is as follows:
from os import path
from tinytag import TinyTag
def create_search_term(file_path_to_song):
"""
Takes in a file path to a song and returns a phrase that will be used to search for the song's corresponding album artwork.
:param file_path_to_song: a file path to an .mp3 or .m4a file.
:type file_path_to_song: `string`, required.
:return: an object of type string that represents the search term to be used when finding album artwork for song file passed into the function.
:rtype: `string`.
"""
if str(path.isfile(file_path_to_song)):
tag = TinyTag.get(file_path_to_song)
album = tag.get_album()
artist = tag.get_artist()
term = f"{artist} {album} Album Cover"
return term
else:
return False
I would like to write a test for create_search_term() using the Mock Object Library. In the test_module.py function, I have the following:
from unittest import TestCase
from mock import patch
import unittest
from artwork_grabber.helpers import create_search_term
class UnitTests(TestCase):
mock_song_info = {
"album": "A Deeper Understanding",
"artist": "The War On Drugs"
}
# patch where the function is USED, not where it is DEFINED
#mock.patch('artwork_grabber.helpers.create_search_term', return_value=mock_song_info)
def test_create_search_term(self, mock_song):
actual_result = create_search_term(mock_song_info)
expected_result = "A Deeper Understanding The War On Drugs Album Cover"
self.assertEqual(actual_result, expected_result,
"Expected the search terms to match.")
if __name__ == "__main__":
unittest.main()
The problem is that when I run python test_module.py from the terminal (where pwd outputs /path/to/artwork_grabber/tests), I get the following error:
Traceback (most recent call last):
File "test_module.py", line 5, in <module>
from artwork_grabber.artwork_grabber import create_search_term
ModuleNotFoundError: No module named 'artwork_grabber'
Any idea what I might be missing? I've viewed several tutorials on using Mock, but they haven't seemed to help.
As documented in The Module Search Path:
When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:
The directory containing the input script (or the current directory when no file is specified).
PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
...
So in your case, the path that python would look for your modules is at /path/to/artwork_grabber/tests which obviously doesn't contain any artwork_grabber/helpers.py since it only contains an __init__.py and test_module.py. To satisfy either of the 2 ways above as documented, do either of the following:
Go to the parent folder cd /path/to/artwork_grabber and then execute the test python tests/test_module.py. This will satisfy the 1st above which will include the current path thus including artwork_grabber/helpers.py and the subdirectories and files in it.
Define it in the variable export PYTHONPATH=${PYTHONPATH}:/path/to/artwork_grabber to satisfy the 2nd above.
Note that as pointed out by #MatiasCicero it wouldn't make sense to mock function-x to return y and assert that function-x returned y, the point of testing is to test source code, not to test the test if it correctly did the mock. Ideally, you should run the actual create_search_term and pass it a test file file_path_to_song.

How to import a class from another file in python?

Im new to python and have looked at various stack overflow posts. i feel like this should work but it doesnt. How do you import a class from another file in python?
This folder structure
src/example/ClassExample
src/test/ClassExampleTest
I have this class
class ClassExample:
def __init__(self):
pass
def helloWorld(self):
return "Hello World!"
I have this test class
import unittest
from example import ClassExample
class ClassExampleTest(unittest.TestCase):
def test_HelloWorld(self):
hello = ClassExample()
self.assertEqual("Hello World!", hello.helloWorld())
if __name__ == '__main__':
unittest.main()
When the unit test runs the object is None:
AttributeError: 'NoneType' object has no attribute 'helloWorld'
What's wrong with this? How do you import a class in python?
If you're using Python 3, then imports are absolute by default. This means that import example will look for an absolute package named example, somewhere in the module search path.
So instead, you probably want a relative import. This is useful when you want to import a module that is relative the module doing the importing. In this case:
from ..example.ClassExample import ClassExample
I'm assuming that your folders are Python packages, meaning that they contain __init__.py files. So your directory structure would look like this.
src
|-- __init__.py
|-- example
| |-- __init__.py
| |-- ClassExample.py
|-- test
| |-- __init__.py
| |-- ClassExampleTest.py

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

How to import only functions in a script with custom package/module in Python?

I'm building a package and a noticed that when I import the submodules, they include all of the built-ins that I've imported as well. Is there a way to get around this so when I navigate the submodule with tab complete only the functions and objects from the script are present?
For example, when I import examplemodule.submodule to only see function_i_want when I'm navigating the package contents?
Directory structure
examplemodule
| __init__.py
| submodule
| __init__.py
| submodule.py
examplemodule | submodule | submodule.py
from collections import *
def function_i_want():
return True
Here's an example of what I can import from the module:
>>> import examplemodule
>>> from examplemodule import submodule
>>> submodule.
submodule.AsyncGenerator( submodule.MappingView(
submodule.AsyncIterable( submodule.MutableMapping(
submodule.AsyncIterator( submodule.MutableSequence(
submodule.Awaitable( submodule.MutableSet(
submodule.ByteString( submodule.OrderedDict(
submodule.Callable( submodule.Reversible(
submodule.ChainMap( submodule.Sequence(
submodule.Collection( submodule.Set(
submodule.Container( submodule.Sized(
submodule.Coroutine( submodule.UserDict(
submodule.Counter( submodule.UserList(
submodule.Generator( submodule.UserString(
submodule.Hashable( submodule.ValuesView(
submodule.ItemsView( submodule.defaultdict(
submodule.Iterable( submodule.deque(
submodule.Iterator( submodule.function_i_want(
submodule.KeysView( submodule.namedtuple(
submodule.Mapping( submodule.submodule
When you say from x.y import * you are importing everything defined in __all__ from the module y that resides in directory x.
If you'd only like to import a subset of y you can do the following:
Limit what you're importing from your script
from examplemodule.submodule import function_i_want
or
from examplemodule.submodule import (
function_i_want,
other_function_i_want
)
Define __all__ in your __init__.py
__all__ = ['function_i_want', 'other_function_i_want']
what you could do is import just the module e.g.
import examplemodule
examplemodule.submodule
what this does is only calls the function if you write the module first then .submodule. this is also good if you have more than one module

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

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)

Categories

Resources