[Python] Using a Package in Maya

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.

for example:


myfolder
    __init__.py
   prefs.py
   utilsFolder
       __init__.py
       selectionFolder
           __init__.py
           selectionTool.py 

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.

thanks guys!

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?

I also am confused by this. I don’t understand why I can do something like the following:

import os
os.path.isfile('C:/somefile.txt')

But in my own package setup, the following gives me an error.

import testPackage
testPackage.testModule.testFunction()

AttributeError: ‘module’ object has no attribute ‘testModule’

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:


import sys
sys.path.append(r'C:\someDir')

import testPackage.testModule
testPackage.testModule.testFunction()

[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:


import sys
sys.path.append(r'C:\someDir')

import testPackage.testModule
testPackage.testModule.testFunction()

[/QUOTE]

The Python path is not a problem. Let me rephrase a bit. If I say:

import testPackage.testModule
testPackage.testModule.testFunction()

then the code works fine.

If I say:

import testPackage
testPackage.testModule.testFunction()

then I get the error “AttributeError: ‘module’ object has no attribute ‘testModule’” .

What I’m having trouble understanding is why this doesn’t work, when it works for something like “os”.

ok, so maybe os module is a bad example, since it isn’t even a package.

what i’ve managed to come up with so far is this:

myFolder init is empty

utilsFolder init contains:


from utils.py import *
import selectionFolder
__all__ = ['utils']

selectionFolder init contains:


from selectionTools import *
__all__ = ['selectionTools']

am i on the right track, or am i completely missing the point?
again this is my goal:


import utilsFolder as utils
utils.someUtilFunction()
utils.selectionFolder.someSelectionFunction()

Thanks for bearing with me…

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.

rgkovach123:

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()

I think you want this:



# 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’:

/namespace/init.py: empty
/namespace/subnamespace/init.py: contains foo directly
-or-
/namespace/subnamespace/init.py: “from .foo import foo”
/namespace/subnamespace/foo.py : “def foo…”

Compound package where you want “import namespace; namespace.subnamespace.foo()”
/namespace/init.py: “import .subnamespace”
/namespace/subnamespace/init.py: contains foo directly
-or-
/namespace/subnamespace/init.py: “from .foo import foo”
/namespace/subnamespace/foo.py : “def foo…”

Manually edited where you want “from namespace import foo” but foo is not in namespace.init.py
/namespace/init.py: “from .subnamespace import *”
/namespace/subnamespace/init.py: contains foo directly
-or-
/namespace/subnamespace/init.py: “from .foo import *; all = [‘foo’]”
/namespace/subnamespace/foo.py : “def foo…”

Note that generally I’d recommend against that last one: two layers of nested * imports is asking for a name clash. To quote the masters:

Namespaces are one honking great idea – let’s do more of those!

I understand much better now. (I feel rather foolish for thinking that “os” was a package. :(:slight_smile: 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.

thanks for the clarification!

[QUOTE=Theodox;21662]I think you want this:



# 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’:

/namespace/init.py: empty
/namespace/subnamespace/init.py: contains foo directly
-or-
/namespace/subnamespace/init.py: “from .foo import foo”
/namespace/subnamespace/foo.py : “def foo…”

Compound package where you want “import namespace; namespace.subnamespace.foo()”
/namespace/init.py: “import .subnamespace”
/namespace/subnamespace/init.py: contains foo directly
-or-
/namespace/subnamespace/init.py: “from .foo import foo”
/namespace/subnamespace/foo.py : “def foo…”

Manually edited where you want “from namespace import foo” but foo is not in namespace.init.py
/namespace/init.py: “from .subnamespace import *”
/namespace/subnamespace/init.py: contains foo directly
-or-
/namespace/subnamespace/init.py: “from .foo import *; all = [‘foo’]”
/namespace/subnamespace/foo.py : “def foo…”

Note that generally I’d recommend against that last one: two layers of nested * imports is asking for a name clash. To quote the masters:[/QUOTE]

When I try this syntax I get a Syntax Error:

import .selection

where selection is a folder containing an init.py file.

according to 1 source on the internets, the correct syntax is:


from . import selection

Am I missing something? thanks again for your help.

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