0

I'm trying to add a directory where I can throw some pyc files and call them from my script.

Basically it's an independent python script with a bunch of def's in it, I want the name of the pyc file to be the command executed. so far this works ok except for one thing, my GUI buttons are calling defs as they are and python doesn't recognize them since the name space is wrong.

How can I import it in from the script as if it was imported like :

from Module import as *

I'm running this code to load it in:

def importModule(ModPath):
    fullModName= ModPath.split('\\')[-1]
    commandtorun=fullModName.split('.')[0]

    mod_name,file_ext = os.path.splitext(os.path.split(ModPath)[-1])
    if file_ext.lower() == '.py':
        py_mod = imp.load_source(mod_name, ModPath)
    elif file_ext.lower() == '.pyc':
        py_mod = imp.load_compiled(mod_name, ModPath)

    exec "from %s import *"%(commandtorun)
    exec "%s()" % (commandtorun)

i know i can write : module.somefunction() , but that's not what i need... i need the "module" to work independently..

Please help, this is driving me crazy, python is such an awesome language I cant believe you can't source a script from within a script and have it work. please advise.

2
  • Don't "source" pyc files if such can be avoided. Consider them an artifact of a particular implementation. Commented Jan 19, 2014 at 10:32
  • didn't get that... sorry .. Commented Jan 19, 2014 at 14:10

3 Answers 3

1
  • You could use a (rare-in-Python) semicolon in your exec call to make one exec out of the two you have
  • You might want to take a look at import_module(name, package) in importlib
Sign up to request clarification or add additional context in comments.

Comments

0

AFAIK exec has it's own variable scope, thereby importing your script into a scope that is immediately destroyed. You could either pass in dicts for the globals and locals or avoid exec completely, which would be my suggestion. Why don't you just use from ... import * directly?

If you place an __init__.py file in the directory, you can use from folder.script import * and if the folder is not in your current working directory or your path, you

  1. are probably doing something wrong, you should have one project directory (that can of course have subdirectories) where your code is; or create multiple modules that you install seperately and make sure the ones you need are in your path
  2. can add any directory to your path, so you can import modules directly from it with

    import sys
    sys.path.append("/path/to/directory")
    

8 Comments

You can pass exec the local scope with the locals and globals parameters.
That's what I thought - and it confirms my theory, but I still think you shouldn't need exec to import modules. That's why I pointed out another way to do it.
can __init__.py be a __init__.pyc as well? its the same file as my script.pyc just rename it yea?
It can be __init__.pyc as well, it is however meant to do initialization of stuff in your module. You don't need this functionality here. Just create an empty Python file, leave the scrypt the way it is and you're good to go.
OK, I cant use from ... import * as it gives this error: import * only allowed at module level,Thats why i used the exec option, as it allowed me to run it, ill try the __init__ way . hope it works.. brb
|
0

If you want to auto-exec a def inside an already imported module, you can do it more simply with the inspect module:

import inspect
def auto_exec (module):
    for fn_name, fn in inspect.getmembers(module, isfunction):
        if fn_name == module.__name__:  fn()

However that's a bandaid on the real problem.

Popping things into the global namespace is an invitation to problems because there is now way to be sure that the function named X you're calling from the global space is the X you want - lots of different modules use similar function names and without namespaces you can't be sure you're getting what you want. It's like voluntarily embracing Javascript style global bugs.

It sounds like you're calling the scripts mel-style with strings? Don't. In python you want to use 'import' to initialize modules and make them available, and it's fine to import the same module multiple times in multiple places. You want to do it without the * so you keep things in predictable order: This is fine python but would be impossible with * imports:

 import legs
 import arms

 legs.rig(cmds.ls("*leg"))
 arms.rig(cmds.ls("*arm"))

As for calling the functions in GUI, the global namespace only matters if you're trying to call the function with strings. Pass in the python functions directly as functions:

 def example(*args):
     print args

 b = cmds.button("test", c= example) # this could also be "somemodule.example" if you import somemodule

As long as example is defined at the time you create the button, this works without any global namespace monkeying. It's very common to manage this using a class so that the callback goes to a class function: that makes it really easy to manage what's going on.

BTW, If you need to pass arguments to the gui calls, the cheap way to do this is to use functools.partial which is designed for bundling args and callables just this way:

from functools import partial
import my_module 

# somewhere in gui

my_button = cmds.button ("test", c = partial(my_module.my_function, "this works"))

There's a bunch of discussion on this problem over at Tech-Artists.org

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.