Python's help function executes another program "string.py" - python

I've been messing around with python a little bit and have created a program saved as string.py where I tested out some string functions.
In another program function.py in the same directory I wrote this code
def say_hi(first = 'John', last = 'Doe'):
"""Say hello."""
print('Hi {} {}!'.format(first, last))
help(say_hi)
which, however, executed the string.py program. I found out after some testing that renaming string.py to anything else solves the problem and the function.py program is executed as intended, but I'd like to understand why the help function executed the other program in the first place.

You are shadowing the name string, which is a built-in module: https://docs.python.org/3/library/string.html
string is a commonly used module. Lots of built-in functions in python run scripts that have import string in them, meaning it'll import your string.py and not the built-in one.
This is just yet another example of why it's a bad idea to name scripts or variables with names that already exist in standard Python.

Related

functions in modules are getting executed first and print statements are not getting executed even after placing them first(Before the function call)

I am new to python and trying out my own pet project. So, my project directories look like this:
Now in my main.py file I have imported models module
from models.eq_melting import * from models.frac_melting import *. After that I put some print statements :
Now the problem is whatever function that is residing in files of module models, is getting executed first rather than the print statements.
Please help me to understand why this is happening.
When you import a module you are in fact executing it, so every statement in the module will get run. If it is just function defs then you will just add those functions to the namespace, but not actually run the code they contain. However if it contains print or other statements then they will get executed.
To summarise when you import a module you execute everything in that module.
This is also why you see very often code that looks like
if __name__ == "__main__" at the bottom of many modules. If the module gets imported the if condition won't be satisfied, but if the module is executed directly as a script then the if condition will be satisfied and the code will run.
As a side note you should do your best to avoid from module import * - it will make debugging ten times harder as it makes it impossible for the computer (and the human) to know where items in its name space came from.

How can I get the directory from a script called by another script in python via a function imported [duplicate]

When writing throwaway scripts it's often needed to load a configuration file, image, or some such thing from the same directory as the script. Preferably this should continue to work correctly regardless of the directory the script is executed from, so we may not want to simply rely on the current working directory.
Something like this works fine if defined within the same file you're using it from:
from os.path import abspath, dirname, join
def prepend_script_directory(s):
here = dirname(abspath(__file__))
return join(here, s)
It's not desirable to copy-paste or rewrite this same function into every module, but there's a problem: if you move it into a separate library, and import as a function, __file__ is now referencing some other module and the results are incorrect.
We could perhaps use this instead, but it seems like the sys.argv may not be reliable either.
def prepend_script_directory(s):
here = dirname(abspath(sys.argv[0]))
return join(here, s)
How to write prepend_script_directory robustly and correctly?
I would personally just os.chdir into the script's directory whenever I execute it. It is just:
import os
os.chdir(os.path.split(__file__)[0])
However if you did want to refactor this thing into a library, you are in essence wanting a function that is aware of its caller's state. You thus have to make it
prepend_script_directory(__file__, blah)
If you just wanted to write
prepend_script_directory(blah)
you'd have to do cpython-specific tricks with stack frames:
import inspect
def getCallerModule():
# gets globals of module called from, and prints out __file__ global
print(inspect.currentframe().f_back.f_globals['__file__'])
I think the reason it doesn't smell right is that $PYTHONPATH (or sys.path) is the proper general mechanism to use.
You want pkg_resources
import pkg_resources
foo_fname = pkg_resources.resource_filename(__name__, "foo.txt")

"Sourcing" python scripts with multiple defs - MAYA

So I've been doing a lot of research and couldn't find a proper answer. I'm quite new to python so sorry if this is a simple question.
So, basically, I'm creating an UI that has a button that should call a function from another .py file. What I did so far is append the file's folder to sys.path and import the .py file as something else. Example, let's say I'm importing myTools.py:
import myTools as mt
Now I can successfully access all functions within myTools via mt.mainFunction() or anything with the mt. prefix.
Now my question:
When I run mt.myFunction() directly it works just fine. Problem is that mainFunction() is another UI that calls different functions at different times. All these functions are on the myTools file.. but Maya won't find them because when they are called within the mainFunction() they don't have the mt prefix.
I mean, I could run those defs on the userSetup.py but it's quite a big code and I wanted to do that the cleanest way :)
Any ideas?
Thanks in advance!
EDIT:
So I just realized is only one function that isn't working. I'm getting this error:
# Error: NameError: file <maya console> line 1: name 'annotationToLocator' is not defined #
Because of that error, I thought that my mainfunction couldn't find any other function on the module.
The actual code where I declare this function:
jobNum = cmds.scriptJob(e=['SelectionChanged', 'annotationToLocator()'])
def annotationToLocator ():
selList = cmds.ls(sl=True)
for item in selList:
if '_ANN' in str(item):
cmds.select(item,d=True)
newItem = str(item).replace('_ANN', '_LOC')
cmds.select(newItem,add=True)
A couple of weird things about this:
1) It works perfectly when I run the code directly.
2) I'm importing the module on the userSetup file.. I'm getting the error above not only when I try to actually run the function that calls this one, but also when Maya starts..
I tried commenting the scriptjob line and now it works just fine, although obviously now I don't have the scriptjob running. I think is some issue with modules and scriptjobs?!
I'm sorry, I know I got off of the original question path here! :)
This sounds like typical python behaviour and should work correctly. Each module has it's own global scope and each function defined in that module will have access to everything defined in that scope.
So in the myTools module each function has access to each other by name, and every function defined in your main module will have access to the mt module object and can get the functions as it's attributes.
You problem stems from using string references to your function. While that works, it only works if they function you're calling by string is in the global python scope -- which usually means it only works in the listener.
The better way to do any maya callbacks is by passing the functions directly to the callback as function objects, not as strings:
import mymodule
cmds.scriptJob(e=('somethingSelected', mymodule.fancyfunction))
Note that mymodule.fancyfunction is passed without parens: you are telling Maya "use this function." If you did it as mymodule.fancyfunction() you'd be telling Maya to use the result of a call to the function , not the function itself.

Pass variable between python scripts

I'm sure this is very simple but I've been unable to get it working correctly. I need to have my main python script call another python script and pass variables from the original script to the script that I've called
So for a simplistic example my first script is,
first.py
x = 5
import second
and my second script is,
second.py
print x
and I would expect it to print x but I get
NameError: name 'x' is not defined
I'm not sure if import is right way to achieve this, but if someone could shed light on it in a simple way that would be great!
thanks,
EDIT
After reading the comments I thought I would expand on my question. Aswin Murugesh answer fixes the import problem I was having, however the solution does not have the desired outcome as I can not seem to pass items in a list this way.
In first.py I have a list which I process as follows
for insert, (list) in enumerate(list, start =1):
'call second.py passing current list item'
I wanted to pass each item in the list to a second python file for further processing (web scraping), I didn't want to do this in first.py as this is meant to be the main 'scan' program which then calls other programs. I hope this now make more sense.
Thanks for the comments thus far.
When you call a script, the calling script can access the namespace of the called script. (In your case, first can access the namespace of second.) However, what you are asking for is the other way around. Your variable is defined in the calling script, and you want the called script to access the caller's namespace.
An answer is already stated in this SO post, in the question itself:
Access namespace of calling module
But I will just explain it here in your context.
To get what you want in your case, start off the called script with the following line:
from __main__ import *
This allows it to access the namespace (all variables and functions) of the caller script.
So now your calling script is, as before:
x=5
import second
and the called script is:
from __main__ import *
print x
This should work fine.
use the following script:
first.py:
x=5
second.py
import first
print first.x
this will print the x value. Always imported script data should be referenced with the script name, like in first.x
To avoid namespace pollution, import the variables you want individually: from __main__ import x, and so on. Otherwise you'll end up with naming conflicts you weren't aware of.
Try use exec
Python3.5:
first.py
x=5
exec(open('second.py').read())
second.py
print(x)
You can also pass x by using:
x=5
myVars = {'x':x}
exec(open('second.py').read(), myVars)
Not sure if this is a good way.
Finally,
I created a package for Python to solve this problem.
Install Guli from PIP.
$ pip install guli
Guli doesn't require installing any additional PIP package.
With the package you can
Guli can be used to pass between different Python scripts, between many processes or at the same script.
pass variables between main Process and another (Multiprocess) Process.
Pass variables between different Python scripts.
Pass variables between 'Main Process' and another (Multiprocess) Process.
Use variables at the same script.
Create / Delete / Edit - GuliVariables.
Example
import guli
import multiprocessing
string = guli.GuliVariable("hello").get()
print(string) # returns empty string ""
def my_function():
''' change the value from another process '''
guli.GuliVariable("hello").setValue(4)
multiprocessing.Process(target=my_function).start()
import time
time.sleep(0.01) # delay after process to catch the update
string = guli.GuliVariable("hello").get()
print(string) # returns "success!!!"
Hope I solved the problem for many people!

python NameError: name '<anything>' is not defined (but it is!)

Note: Solved. It turned out that I was importing a previous version of the same module.
It is easy to find similar topics on StackOverflow, where someone ran into a NameError. But most of the questions deal with specific modules and the solution is often to update the module.
In my case, I am trying to import a function from a module that I wrote myself. The module is named InfraPy, and it is definitely on sys.path. One particular function (called listToText) in InfraPy returns a NameError, but only when I try to import it into another script. Inside InfraPy, under if __name__=='__main__':, the listToText function works just fine. From InfraPy I can import other functions with no problems. Including from InfraPy import * in my script does not return any errors until I try to use the listToText function.
How can this occur?
How can importing one particular function return a NameError, while importing all the other functions in the same module works fine?
Using python 2.6 on MacOSX 10.6, also encountered the same error running the script on Windows 7, using IronPython 2.6 for .NET 4.0
Thanks.
If there are other details you think would be helpful in solving this, I'd be happy to provide them.
As requested, here is the function definition inside of InfraPy:
def listToText(inputList, folder=None, outputName='list.txt'):
'''
Creates a text file from a list (with each list item on a separate line). May be placed in any given folder, but will otherwise be created in the working directory of the python interpreter.
'''
fname = outputName
if folder != None:
fname = folder+'/'+fname
f = open(fname, 'w')
for file in inputList:
f.write(file+'\n')
f.close()
This function is defined above and outside of if __name__=='__main__':
I've tried moving InfraPy around in relation to the script. The most baffling situation is that when InfraPy is in the same folder as the script, and I import using from InfraPy import listToText, I receive this error: NameError: name listToText is not defined. Again, the other functions import fine, they are all defined outside of if __name__=='__main__': in InfraPy.
This could happen if the module has __all__ defined
Alternatively there could be another version of the module in your path that is getting imported instead of the one you are expecting
Is the NameError about listToText or is it something inside the function causing the exception?
In addition the __all__ variable gnibbler mentioned you could also have a problem with a InfraPy.pyc file lying around somewhere.
I'd recommend putting a import pdb;pdb.set_trace() first in the InfraPy.py file to make sure you are in the right file, and step through the definition of InfraPy.py to see what is happening. If you don't get a breakpoint, you are importing another file than you think.
You can also dir(InfraPy) after importing it, and check which file you are actually importing with InfraPy.__file__.
Can't think of any more import debugging hints right now. ;-)

Categories

Resources