Python os.getenv returning None, missing var on Windows 10 - python

( >= Python 3.4 )
With os.getenv(), i am not able to retrieve some env vars, like %DATE% or %TIME%,
ex:
print(os.getenv('computername')) # works
print(os.getenv('date')) # not working, returning None
print(os.getenv('time')) # not working, returning None
So i checked the list of var env python can detect by this:
[print(var) for var in os.environ]
It result a list of lot of env, but missing date, and time, at least.
A strange thing is the last item of the list is a list of None objects, probably the missing var env, but only appearing when using the interactive console.. and thus not really in the list.. or maybe some artifacts of the print function used in the interactive console?
Try
import os
varenv = [var for var in os.environ]
[print(var) for var in varenv]`
with the interactive console from the command line
Finally, when your are in windows cmd, echo %date% %computername% works great, with no different processing between these var.
I presume it's maybe related with unicode, but havent found any answers yet in my researches: Why %DATE% or %TIME% not working while %computername% just fine ?

In fact, %DATE% and %TIME% are not environment variables.
See this Microsoft documentation User Environment Variables to see the list of environment variables of your system.

Related

Getting the value from python script into a powershell script

I have python script which creates a ticket.
I need to invoke the python script from within powershell script and
get the ticketnumber(12 digit long).
Approach#1:
I tried to use the exit(ticket_number) to get this done.It worked well as long as the number is not very large.
Ex.
exit(12345) from python translates to $LASTEXITCODE=12345 #good
exit(123456789123) from python translates to $LASTEXITCODE=-1 #not sure what is going wrong here
dummy.py
--------
print("hello")
exit(123456789123)
sample.ps1
----------
python dummy.py
Write-Host($LASTEXITCODE)
Approach#2:
Use of env variable
dummy.py
--------
import os
os.environ["TICKETNUMBER"] = "123456789123"
exit(0)
sample.ps1
----------
Get-ChildItem -Path Env:TEMP # good - able to get value
Get-ChildItem -Path Env:TICKETNUMBER # - error - ItemNotFoundException
So, I would like to know what is going wrong in each of the approaches.
Are there any better approaches to get this done - Please suggest.
You should not use exit codes to output a value, this simply isn't what they're meant to do. You can read more about exit codes here: https://shapeshed.com/unix-exit-codes/#what-is-an-exit-code-in-the-unix-or-linux-shell
Environment variables only work for passing around values when you're passing them to children. If you spawn a new process, said process will inherit the environment variables in scope of your current session. However, you can't change the environment variables of the parent (your session) from the child (the python runtime). Thus, in Powershell, your "TICKETNUMBER" environment variable is out of scope.
First of all let me say that there are many different ways to go about solving this. The solution that requires the least amount of work on your part would be to output to stdout, which allows you to output values for consumption by other processes. You can do this with print in python. You already did this but likely ran into issues due to your use of exit codes.
In Powershell, you can accept this input via the pipeline. There are a lot of ways to go about this, but in your example the $input variable will work.
dummy.py
--------
print("123123123")
sample.ps1
--------
Get-ChildItem -Path $input
You can then run py dummy.py | ./sample.ps1, which will return the directory listing of "./123123123".

IDLE autocomplete in a new file do not work

If I testing my codes on IDLE the autocomplete its works but if I open a new file don't.
See there pictures below:
I just press CTRL + SPACE.
So.. don't work in this case:
I'll think there are some configuration for solve this, any one knows?
Python idle doesn't work that way. You get autocomplete in idle shell because values are deduced in every run. When you use files your program is not evaluated until you run. Because you can assign any type to a variable at run time, there is no way for idle to confirm the type of variable.
Understand with an example
>> a = dict()
>> a = set()
>> a. # <-- autocomplete knows type of a is set
but the same code in a file
a = dict()
a = set()
a. # <-- How does idle come to know what this variable is without running
but when you run this file once your global variables will show autocomplete feature, but not the local scope variables.
Have you tried saving the script as a *.py file before trying to use IDLE's autocomplete?
More than that, have you considered using a text editor with Python plugins, like Sublime Text and Atom? Or even a python-compatible IDE, like PyCharm, Spyder or even JupyterNotebook.

%USERPROFILE% env variable for python

I am writing a script in Python 2.7.
It needs to be able to go whoever the current users profile in Windows.
This is the variable and function I currently have:
import os
desired_paths = os.path.expanduser('HOME'\"My Documents")
I do have doubts that this expanduser will work though. I tried looking for Windows Env Variables to in Python to hopefully find a list and know what to convert it to. Either such tool doesn't exist or I am just not using the right search terms since I am still pretty new and learning.
You can access environment variables via the os.environ mapping:
import os
print(os.environ['USERPROFILE'])
This will work in Windows. For another OS, you'd need the appropriate environment variable.
Also, the way to concatenate strings in Python is with + signs, so this:
os.path.expanduser('HOME'\"My Documents")
^^^^^^^^^^^^^^^^^^^^^
should probably be something else. But to concatenate paths you should be more careful, and probably want to use something like:
os.sep.join(<your path parts>)
# or
os.path.join(<your path parts>)
(There is a slight distinction between the two)
If you want the My Documents directory of the current user, you might try something like:
docs = os.path.join(os.environ['USERPROFILE'], "My Documents")
Alternatively, using expanduser:
docs = os.path.expanduser(os.sep.join(["~","My Documents"]))
Lastly, to see what environment variables are set, you can do something like:
print(os.environ.keys())
(In reference to finding a list of what environment vars are set)
Going by os.path.expanduser , using a ~ would seem more reliable than using 'HOME'.

Load environment variables from a shell script

I have a file with some environment variables that I want to use in a python script
The following works form the command line
$ source myFile.sh
$ python ./myScript.py
and from inside the python script I can access the variables like
import os
os.getenv('myvariable')
How can I source the shell script, then access the variables, from with the python script?
If you are saying backward environment propagation, sorry, you can't. It's a security issue. However, directly source environment from python is definitely valid. But it's more or less a manual process.
import subprocess as sp
SOURCE = 'your_file_path'
proc = sp.Popen(['bash', '-c', 'source {} && env'.format(SOURCE)], stdout=sp.PIPE)
source_env = {tup[0].strip(): tup[1].strip() for tup in map(lambda s: s.strip().split('=', 1), proc.stdout)}
Then you have everything you need in source_env.
If you need to write it back to your local environment (which is not recommended, since source_env keeps you clean):
import os
for k, v in source_env.items():
os.environ[k] = v
Another tiny attention needs to be paid here, is since I called bash here, you should expect the rules are applied here too. So if you want your variable to be seen, you will need to export them.
export VAR1='see me'
VAR2='but not me'
You can not load environmental variables in general from a bash or shell script, it is a different language. You will have to use bash to evaluate the file and then somehow print out the variables and then read them. see Forcing bash to expand variables in a string loaded from a file

Detect where Python code is running (e.g., in Spyder interpreter vs. IDLE vs. cmd)

Is there a way in Python to detect, within a process, where that process is being executed? I have some code that includes the getpass.getpass() function, which is broken in Spyder, and it's annoying to go back and forth between the command line and the IDE all the time. It would be useful if I could add code like:
if not being run from Spyder:
use getpass
else:
use alternative
Here is the solution I ended up using. After reading Markus's answer, I noticed that Spyder adds half a dozen or so environment variables to os.environ with names like SPYDER_ENCODING, SPYDER_SHELL_ID, etc. Detecting the presence of any of these seems relatively unambiguous, compared to detecting the absence of a variable with as generic a name as 'PYTHONSTARTUP'. The code is simple, and works independently of Spyder's startup script (as far as I can tell):
if any('SPYDER' in name for name in os.environ)
# use alternative
else:
# use getpass
Since the string is at the beginning of each environment variable name, you could also use str.startswith, but it's less flexible, and a little bit slower (I was curious):
>>> import timeit
>>> s = timeit.Timer("[name.startswith('SPYDER') for name in os.environ]", "import os")
>>> i = timeit.Timer("['SPYDER' in name for name in os.environ]", "import os")
>>> s.timeit()
16.18333065883474
>>> i.timeit()
6.156869294143846
The sys.executable method may or may not be useful depending on your installation. I have a couple WinPython installations and a separate Python 2.7 installation, so I was able to check the condition sys.executable.find('WinPy') == -1 to detect a folder name in the path of the executable Spyder uses. Since the warning that shows in IDLE when you try to use getpass is less "loud" than it could be, in my opinion, I ended up also checking the condition sys.executable.find('pythonw.exe') == -1 to make it slightly louder. Using sys.executable only, that method looks like:
if sys.executable.find('pythonw.exe') == sys.executable.find('WinPy') == -1:
# use getpass
else:
# use alternative
But since I want this to work on other machines, and it's much more likely that another user would modify their WinPython installation folder name than that they would rename their IDLE executable, my final code uses sys.executable to detect IDLE and os.environ to detect Spyder, providing a "louder" warning in either case and keeping the code from breaking in the latter.
if any('SPYDER' in name for name in os.environ) \
or 'pythonw.exe' in sys.executable:
password = raw_input('WARNING: PASSWORD WILL BE SHOWN ON SCREEN\n\n' * 3
+ 'Please enter your password: ')
else:
password = getpass.getpass("Please enter your password: ")
By default, Spyder uses a startup scrip, see Preferences -> Console -> Adanced setting. This option is usually set to the scientific_startup.py file that loads pylab et al.
The easiest solution is to just add a global variable to the file and then use that in your if statement, e.g. add this line at the end of scientific_startup.py:
SPYDER_IDE_ACTIVE = True
In your script:
if not 'SPYDER_IDE_ACTIVE' in globals():
use getpass
else:
use alternative
This will work without throwing an error. You can also use exceptions if you like that more.
A second solution would be (if you cannot modify that file for some reason) to just check if the environment variable PYTHONSTARTUP is set. On my machine (using the Anaconda Python stack), it is not set for a regular Python shell. You could do
import os
if not 'PYTHONSTARTUP' in os.environ:
use getpass
else:
use alternative
Spyder provides the option of executing the current editor script in a native system terminal. This would produce identical behavior as if you were running from the command line. To set this up, open the Run Settings dialog by hitting F6. Then select the radio button "Execute in an external System terminal". Now run the script as usual by hitting F5. You should be able to use getpass in the normal fashion with this approach.
You could add env variable when running in Spyder and check it in code.

Categories

Resources