cProfile seems to override the normal value of `__file__`, how adapt? - python

I have a program that relies on the __file__ built-in global to provide the path to data associated with the program, as in path_to_stuff = os.path.join(os.path.dirname(__file__),'stuff'). The problem is that when I run this with python -m cProfile myprog, the value of __file__ is no longer the path to myprog but rather (apparently) the path to the cProfile module, where my stuff definitely isn't.
I've read the manual and searched here and don't see anything about this. Is there a way to either (a) get cProfile to leave __file__ alone or (b) know at runtime that I'm running under cProfile so I could initialize the path with a literal string in this special case?
Edit: or, I guess, (c), is there a better way to find a dir that will always be right next to the program.py?

(b) seems easy to do. In your program.py, check the value of __name__ . If you are running the program directly the value of __name__ would be "__main__". Instead, the value will be different if you are running it under cProfile.
Edit: I am unable to replicate your problem. cProfile doesnot seem to change either the __name__ or the __file__ value when I try it. You can also try running the profiler with in you script by calling cProfile.run()

I've found the solution for you if you still have the problem.
path_to_stuff = os.path.join(path.dirname(path.realpath(sys.argv[0])), 'stuff')

Related

Ansible - Testing if called python script is indeed running via Ansible

I'm looking for a way to test, in my python script, if said script is running from Ansible so I can also run it through shell (for running unit tests etc). Calling AnsibleModule without calling from an ansible playbook will just endlessly wait for a response that will never come.
I'm expecting that there isn't a simple test and that I have to restructure in some way, but I'm open to any options.
def main():
# must test if running via ansible before next line
module = AnsibleModule(
argument_spec=dict(
server=dict(required=True, type='str'),
[...]
)
[... do things ...]
)
if __name__ == "__main__":
if running_via_ansible:
main()
else:
run_tests()
I believe there are a couple of answers, with various levels of trickery involved
since your module is written in python, ansible will use the AnsiballZ framework to run it, which means its sys.argv[0] will start with AnsiballZ_; it will also likely be written to $HOME/.ansible/tmp on the target machine, so one could sniff for .ansible/tmp showing up in argv[0] also
if the file contains the string WANT_JSON in it, then ansible will invoke it with the module's JSON payload as the first argument instead of feeding it JSON on sys.stdin (thus far the filename has been colocated with the AnsiballZ_ script, but I don't know that such a thing is guaranteed)
Similar, although apparently far more python specific: if it contains a triple-quoted sentinel """<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>""" (or the ''' flavor works, too) then that magic string is replaced by the serialized JSON that, again, would have been otherwise provided via stdin
While this may not apply, or be helpful, I actually would expect that any local testing environment would have more "fingerprints" than trying to detect the opposite, and has the pleasing side-effect of "failing open" in that the module will assume it is running in production mode unless it can prove testing mode, which should make for less weird false positives. Then again, I guess the reasonable default depends on how problematic it would be for the module to attempt to carry out its payload when not really in use

Setting CWDir as a variable for MS-Dos environment

Can someone help me with this please?
I am trying to compile a program in this case programmed in python that I can run in win9Xdos, that I can call/start from a 9xDos batchfile, that will find the Current working Dir & by that I mean identify the cwd (current working directory) from where the python program and batchfile are executed. The python program will be called getcwd.py which I am hoping someone will outline what I need to do to convert to EXE/COM file. there is a program called Py2EXE but not sure if this will compile for Ms-dos file. Anyways heres my simple code thus far. Can someone tell me if I am on the right track please? Oh by the way what I am trying to do is find the CWD & inject the resultant path into a variable that can be read from 9Xdos. The current Var would be %cwd%
# importing os module
import os
# some websites say use: del cwd (to remove variable if it exists)
cwd = none
cwd = os.getcwd()
print(cwd)
The print line may need interchanging with code below, not sure help needed:
print(type(path))
# <class 'str'>
would the above code work, say in the root e.g. C:\ with & work in obtaining the CWD variable & if correct how would I proceed to compile it to an exe/com file? do I need to take into account LFN's & Spaces between possible paths e.g C:\Program Files & possible backslashes etc?
Your code isn't perfect but it is on the right track. All you need is this:
import os
if __name__ == '__main__':
print(os.getcwd())
There is no need for an auxiliary variable, and I don't know what websites are recommending that you delete the variable before creating it. Trying to delete a nonexistent Python variable is a runtime error. So I would stay away from those websites.
But your question is about setting an environment variable. Calling print() won't do that. All it will do is echo the current working directory to the console. There is no way to change the environment of a running process that will affect the parent process. This is not a Python restriction nor a Windows restriction: it is quite general. The OS sets up the environment of the process when it creates the process. You can make changes to the environment (using os.environ[env-var]) but those changes will only be visible inside that Python process and will not be visible to the environment of the batch file that runs the Python program. To do that, you need to pass the value back to the calling process.
One way to do that is like this:
In Python:
import os
if __name__ == '__main__':
print(f"set CWDIR={os.getcwd()}", file=open("mycd.bat","w"))
I haven't had a Python 1.5.2 environment for 15 years, so I can't test this, but I think the equivalent would have been
if __name__ == '__main__':
print >> open("mycd.bat","w"), "set CWDIR=%s" % (os.getcwd(),)
In a cmd.exe console:
call mycd.bat
Though if your Win9XDos doesn't provide %cd% (which, as far as I recall, was available in MS-DOS 5, or maybe further back still) there is no way of telling if it supports call either. (Are you maybe running command.com instead of cmd.exe? That would explain why things that should be there are missing).
I used pyinstaller to create a 64-bit .exe and that resulted in a file of about 6MB. Now, 32-bit executables are smaller, but it might be that the resulting executable is still too big to load.
So I think the Python route may turn out to be more trouble than it is worth.

For what uses do we need `sys` module in python?

I'm a bit experienced without other languages but, novice with Python. I have come across made codes in jupyter notebooks where sys is imported.
I can't see the further use of the sys module in the code. Can someone help me to understand what is the purpose of importing sys?
I do know about the module and it's uses though but can't find a concise reason of why is it used in many code blocks without any further use.
If nothing declared within sys is actually used, then there's no benefit to importing it. There's not a significant amount of cost either.
Sys module is a rather useful module as it allows you to work with your System and those things. Eg:
You can access any command line arguments using sys.argv[1:]
You can see the Path to files.
Version of your Python Interpreter using sys.version
Exit the running code with sys.exit
Mostly you will use it for accessing the Command Line arguments.
I'm a new pythonista bro, I learned to import it whenever I want to exit the program with a nice exit text in red
import sys
name = input("What's your name? ")
if name == "Vedant":
print(f"Hello There {name}.")
else:
sys.exit(f"You're not {name}!")
The sys includes "functions + variable " to help you control and change the python environment #runtime.
Some examples of this control includes:
1- using other sources data as input via using:
sys.stdin
2- using data in the other resources via using:
sys.stdout
3- writing errors when an exception happens, automatically in :
sys.stderr
4- exit from the program by printing a message like:
sys.exit("Finish with the calculations.")
5- The built-in variable to list the directories which the interpreter will looking for functions in them:
sys.pasth
6- Use a function to realize the number of bytes in anonymous datatype via:
sys.getsizeof(1)
sys.getsizeof(3.8)

How to inspect the type of REPL you're using?

There're many kinds of Python REPL, like the default REPL, ptpython, ipython, bpython, etc. Is there a way to inspect what current REPL is when I'm already in it?
A little background:
As you may have heard, I made pdir2 to generate pretty dir() printing. A challenge I'm facing is to make it compatible with those third-party REPLs, but first I need to know which REPL the program is running in.
Ok, finally found a simple but super reliable way: checking sys.modules.
A function you could copy and use.
import sys
def get_repl_type():
if any('ptpython' in key for key in sys.modules):
return 'PTPYTHON'
if any('bpython' in key for key in sys.modules):
return 'BPYTHON'
try:
__IPYTHON__
return 'IPYTHON'
except NameError:
return 'PYTHON'
Probably the best you can do is to look at sys.stdin and stdout and compare their types.
Maybe there are also ways for each interpreter to hook in custom completions or formatters.
You can try to find information from the call stack.
Those fancy REPLs use their startup script to initialize.
It's possible to run one REPL in another, so you need to traverse call stack from top to bottom until find a frame from REPL init script.

Testing for presence of IPython

I have the same code, which I occasionally run from the command line as python source.py and occasionally copy/paste it into interactive IPython. I would like to execute slightly different code in either way, and tried to embed differences into the following code block:
try:
__IPYTHON__
# do IPython-mode code
except NameError:
# do script-mode code
I know that in Python this is a common technique, but it screws up automated flagging in PyCharm and I was hoping to find some more attractive way to test for the presence of IPython, perhaps by testing '__IPYTHON__' in ... or something similar. However, I saw that this symbol is neither in locals() nor in globals(). Is there any other place I can test for its presence, or any other more conventional test, not using exceptions directly?
I am using Python 2.7.11 and IPython 5.1.0.
Thank you very much.
UPDATE Related but unhelpful: How do I check if a variable exists?
I think you are looking for
if hasattr(__builtins__, '__IPYTHON__'):
print('IPython')
else:
print('Nope')
While the current accepted answer works in the __main__ namespace, it won't work in a package due to __builtins__ being a dict in other namespaces. This should work in any namespace in python3:
import builtins
getattr(builtins, "__IPYTHON__", False)

Categories