I’m trying to create a brand new python package for use in maya and I have a question about init.py files.
According tomost of the information i’ve read online, these can be blank files, but Maya doesn’t seem to be able to find sub-folders of the package - it only finds modules in the root of the package.
I can get to pref.py just fine, but I can’t get to selectionTool.py, python says the module has no attribute.
I can import “myfolder.utilsFolder.selectionFolder” just fine, but when I try dir(myfolder.utilsFolder.selectionFolder) on it, it doesn’t list selectionTool.py.
I have seen other people recommend adding “from blah import *” for each file in the subfolders into the outer most init.py - is this the right answer?
Thanks.
A question about packages and the PythonPath - does only the top folder of a package need to be added to the PythonPath, or do all the subfolders also need to be added as well?
I believe only the top folder should need to be in your sys.path. Every folder under that that has a init.py can then be reached by using the full qualification.
So if ‘myfolder’ is in sys.path, you should be able to:
import utilsFolder.selectionFolder.selectionTool as selectionTool
You can also add code to your init.py file if you want to import everything into that namespace (like you mention), so you wouldn’t need a fully qualified name.
I personally prefer fully qualified names, but I think that’s just preference.
Ah I see now where I was confusing myself. Yes, directly importing the file using the full path does work.
So without extra code in the init.py files to import the contents of the folder into the namespace, I won’t be able to access all the contents of the folder by importing just the folder.
Correct. It is only when importing modules that you can access all the attributes on that module. Importing a package just adds that package (and all parent packages) to sys.modules and executes init.py.
I’m usually explicit in my imports, importing only what modules I know I need, and not having mymodule.tools import every single subpackage and submodule.
It also depends on how you’ve organized your code, and how you want to access it. If you have code broken up into a bunch of granular subpackages and modules for easier navigation/editing, but want to have their functionality grouped under one namespace, then I would include import statements in the init.py file of a package. As an example, the pymel.core init.py file imports all the command modules into the pymel.core namespace (general, modeling, animation) to simplify the access of methods to a single namespace. When doing this you need to be wary of name clobbering though, and not just import a bunch of modules without checking that they will play nice.
EDIT: Also don’t forget if you go the from module import * route in your init.py file, that you should define the all attribute for each module that you import using that method.
if…code defines a list named all, it is taken to be the list of attribute names that should be imported when from module import * is encountered
++ to capper - all the right advice. Packages generall fall into two classes: the ones that are really just bundles of related stuff, with an empty init py and users expected to import submodules directly, or packages with explicit imports and setup where the packages are basically internal. The only way to do the latter and keep your sanity is to add explicit imports to the master init.py.
better to import what you need only, less cluttered nameSpace, and if your using complementation in your ide, it also means there are less and more accurate results.
if you are un sure of what you are useing, you can import a few moduals, and the ide should tell you what isn’t being used after you write the script.
Ok I’m back with another question. I am trying to setup a mix of packages that import their contents into the same namespace, but also packages that require explicit importing.
I am having trouble getting maya to find the modules and functions for the package that imports everything into a single namespace.
I read up on the all variable, but find it a bit confusing - the documentation says it goes into the module to expose functions and variables, but the examples they give they put it in the init file…
When I import my package, they are empty - they aren’t picking up the functions defined in the modules.
I’d like to do some like:
import myFolder.utilsFolder as utils
utils.selectionFolder.selectionTool()
and also do this if I wanted to be more specific:
import myFolder.utilsFolder.selectionFolder as sel
sel.selectionTool()
to rephrase my question, how do i setup a package structure like os, where i can do things like “import os” to access everything, or “import os.path” to get just that submodule.
does it involve a combination of setting all and adding imports to each init file in each subdirectory?
RFlannery, this will only work if testPackage is stored in sys.paths. Start your script with something like this, where someDir contains the folder testPacakge:
[QUOTE=ozzmeister00;21653]RFlannery, this will only work if testPackage is stored in sys.paths. Start your script with something like this, where someDir contains the folder testPacakge:
[QUOTE=RFlannery;21654]What I’m having trouble understanding is why this doesn’t work, when it works for something like “os”.[/QUOTE]
os.path is accessible when you import the os module because path is explicitly imported in the os module. os is not a package either. If you pull open the os module you will see these lines near the top (in the main scope of the function, so it gets run on import)
if 'posix' in _names:
....
import posixpath as path
elif 'nt' in _names:
....
import ntpath as path
The import statement does not import any subpackages when you import a package–you have to be explicit about that.
If you import a package it will run init.py.
If you import a module it will run the module.
You’re on the right track. The all attribute tells python what attributes to import only when using from module import *. It will have no effect on module/package imports done using a different flavor of the import statement. In your example you are defining the all attribute for packages that you are then importing using the import package flavor. With that usage the all attribute will have no effect.
Now, you don’t have to define the all attribute from from module import * to work, it just limits what gets imported, which will help minimize name clobbering (and keep things cleaner) by not importing every attribute defined in the module’s main namespace.
You would want to define the all attribute for utils.py and selectionTools.py, since you are importing those modules using from module import *. Otherwise your logic is correct and assuming that someUtilFunction is defined in utils.py and someSelectionFunction is in selectionTools.py this should work:
import utilsFolder as utils
utils.someUtilFunction()
utils.selectionFolder.someSelectionFunction()
# for the __init__.py in Utils where util_one.py is in the utils folder...
from .util_one import funcname_one, funcname_two
__all__ = ['funcname_one', 'funcname_two']
# in other code:
import myFolder.utils
myFolder.utils.funcname_one()
or, more generically.
Library package where you want ‘from namespace.subnamespace import foo’:
I understand much better now. (I feel rather foolish for thinking that “os” was a package. :( Thanks for all the great examples. I think I’ve got a handle on it now but will ask more questions if I run into more problems.
# for the __init__.py in Utils where util_one.py is in the utils folder...
from .util_one import funcname_one, funcname_two
__all__ = ['funcname_one', 'funcname_two']
# in other code:
import myFolder.utils
myFolder.utils.funcname_one()
or, more generically.
Library package where you want ‘from namespace.subnamespace import foo’:
Sorry - I did that w/o checking it and the reality is a bit messy. Dot syntax does not work for modules but only for their contents. In this context, if ‘selection.py’ lives alongside ‘init.py’, the init can do
from selection import *
from .selection import * # or "from .selection import foo"
from . import selection # though this is usually how subpackages import their container....
#or
import selection
# but not import .selection
Guido has Pronounced [1] that relative imports will use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots give a relative import to the parent(s) of the current package, one level per dot after the first. Here’s a sample package layout:
package/ init.py
subpackage1/ init.py
moduleX.py
moduleY.py
subpackage2/ init.py
moduleZ.py
moduleA.py
Assuming that the current file is either moduleX.py or subpackage1/init.py, following are correct usages of the new syntax:
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from …subpackage1 import moduleY
from …subpackage2.moduleZ import eggs
from …moduleA import foo
from …package import bar
from …sys import path