Determine how environment variable was set - python

In Python I can access an environment variable as:
os.environ['FOO']
I would like to know if the variable was set previously via export or if it was set only for the current python script like so:
FOO=BAR python some-script.py
Basically I want to only use FOO if it was set like in the line above and not permanently defined per export.
Arguments to the python script itself unfortunately are no option here. This is a plugin and the parent application does not allow passing custom arguments it does not understand itself.
I was hoping I somehow could access the exact and full command (FOO=BAR python some-script.py) that started python but it appears like there is nothing like that. I guess if there was a feature like this it would be somewhere in the os or sys packages.

The environment is simply an array of C strings, there is no metainformation there which helps you find out whether or not the invoking shell had the variable marked for export or not.
On Linux, you could examine /proc/(pid)/environ of the parent PID (if you have suitable permissions) to see what's in the parent's permanent environment, but this is decidedly nonportable and brittle.
Spending time on this seems misdirected anyway; let the user pass the environment variable in any way they see fit.

Related

How can I change the default pager for Python's help() debugger command?

I'm currently doing some work in a server (Ubuntu) without admin rights nor contact with the administrator. When using the help(command) in the python command line I get an error.
Here's an example:
>>> help(someCommand)
/bin/sh: most: command not found
So, this error indicates that most pager is not currently installed. However, the server I'm working on has "more" and "less" pagers installed. So, how can I change the default pager configuration for this python utility?
This one is annoyingly difficult to research, but I think I found it.
The built-in help generates its messages using the standard library pydoc module (the module is also intended to be usable as a standalone script). In that documentation, we find:
When printing output to the console, pydoc attempts to paginate the output for easier reading. If the PAGER environment variable is set, pydoc will use its value as a pagination program.
So, presumably, that's been set to most on your system. Assuming it won't break anything else on your system, just unset or change it. (It still pages without a value set - even on Windows. I assume it has a built-in fallback.)
You can make a custom most script that just invokes less (or even more).
The steps would be:
Set up a script called most, the contents of which are:
#!/bin/sh
less ${#:1} # wierdess is just "all arguments except argument 0"
Put that script in a location that is on your PATH
Then most filename should just run less on that file, and that command should get called from in your python interpreter.
To be honest though, I'd just use Karl's approach.
You can view the various pager options in the source code. That function can be replaced to return whatever is desired. For example:
import pydoc
pydoc.getpager = lambda: lambda text: pydoc.pipepager(text, 'less')

What is the use of os.getenv("HOME") in QFileDialog creation?

Like I said in the title I don't get what os.getenv("HOME") does in this code. I am following a course on an online site and the tutor was coding an interface with PyQt5 similar to notepad. I searched for an answer but they are a bit too advanced I guess. Also I have no idea what an environment variable is. By the way this is my first question on stack so excuse me for any possible mistakes and insufficient information.
def open_file(self):
file_name=QFileDialog.getOpenFileName(self,"Open File",os.getenv("HOME"))
with open(file_name[0],"r") as file:
self.writing_ar.setText(file.read())
The function above is connected to a button self.open such as self.open.clicked.connect(self.open_file)
And self.writing_ar is a QTextEdit object
In the case of os.getenv('HOME'), it's a UNIX-centric way to get the current user's home directory, which is stored as an environment variable per POSIX specification. A typical home directory location is /Users/yourname on MacOS, or /home/yourname on Linux, or c:\Users\Your Name on Windows -- so that's what this code is trying to look up.
The set of environment variables is effectively a key/value store, mapping strings to other strings, that is copied from any program to other processes it starts; they're thus a way to share configuration and other information between programs (though it only shares information down the tree, propagated only on process creation; changes made by a child process are not seen by its parent; and changes to a parent's environment after a child is started are not seen by the child).
If you want something that works reliably even on Windows, consider os.path.expanduser("~") instead. Thus, your code might become:
file_name = QFileDialog.getOpenFileName(self,
"Open File",
os.path.expanduser("~"))
See also What is the correct cross-platform way to get the home directory in Python?
It basically gets an environment variable for you and cast that onto a python variable.
From the code you shared, there should be a variable defined at the operating system level named HOME.
In Linux, that can be done with
export HOME="something_here"
You can check that this variable has actually been defined by typing
echo "$HOME"
in the terminal.
You can think of the os.getenv() method like it "echoes" the value of that argument onto some variable.

Passing modified environment using subprocess

I have a script that adds variables to the environment. That script is called through
subprocess.call('. myscript.sh', shell=True)
Is there a way I can get the modified environment and use it on my next subprocess call?This questions shows you can get the output of one call and chain it to another call Python subprocess: chaining commands with subprocess.run.Is there something similar with passing the environment?
You'll have to output the variables' content somehow. You're spawning a new process which will not propagate the environment variables back, so your python app will not see those values.
You could either make the script echo those to some file, or to the standard output if possible.
(Technically, it would be possible to stop the process and extract the values if you really wanted to hack that, but it's a bad idea.)

Im in the beginning of the Flask tutorial for python, and I dont understand this paragraph

Usually, it is a good idea to load a configuration from a configurable file. This is what from_envvar() can do, replacing the from_object() line above:
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
That way someone can set an environment variable called FLASKR_SETTINGS to specify a config file to be loaded which will then override the default values. The silent switch just tells Flask to not complain if no such environment key is set.
I am not too familiar with environment variables. I would like an explanation of the above paragraph in simple terms. My best guess is that when the program reads FLASKR_SETTING does that mean that on my own computer I have set up a mapping to this file with that name with something called an environment variable? Ive messed with my environment path before and to be honest I still don't understand it, so I came here looking for a clear answer
Environment variables are a name,value pair that are defined for a particular process running on a computer (windows or UNIX/LINUX etc.). They are not files. You can create your own environment variables and give it any name/value. For example, FLASKR_SETTING is the name of the environment variable who value could be set to a config file. On a UNIX terminal for example, you can do:
export FLASKR_SETTING = /somepath/config.txt
By doing the above, you have just created an environment variable named FLASKR_SETTING whose value is set to /somepath/config.txt. The reason you use environment variables is because you can tie them to a certain process and use on demand when your process starts. You don't have to worry about saving them in a file. In fact, you can create a launch script for your process/application that can set a variety of environment variables before you starting using the application.
In case of flask, app.config.from_envvar('FLASKR_SETTINGS', silent=True) sets the value of FLASKR_SETTINGS to the value from the env. variable. So it basically translates to:
- Find the config file (/somepath/config.txt etc.)
- lets say the contents of config file is:
SECRET_KEY="whatever"
DEBUG = True
- Then using the 2 above, it will be translated to:
app.config['SECRET_KEY'] = "whatever"
app.config['DEBUG'] = True
So this way, you can just update the config file as needed and you will not need to change your code.
Environment variables are a simple, ad-hoc way of passing information to programs. On unixy machines, from a command shell, it's as simple as
export FLASKR_SETTINGS=/path/to/settings.conf
/path/to/program
This is especially useful when installing programs to start up at reboot; the configuration can be easily included in the same setup script that launches the system program.

Set environment variable for use with getenv (not GetEnvironmentVariable)

I have a DLL obtaining startup options using getenv (<stdlib.h>) call. I would like to set that variable in the same process, before opening the DLL, so that it is accessible via getenv. Which function should I use to set it?
I learned that there are two sets of env vars under windows: one is manipulated via win32 API (GetEnvironemntVariable, SetEnvironmentVariable), another one can be read using getenv, and probably set via _putenv, is that the one I should use?
Is this function accessible from python, perhaps via ctypes?
The current ~VS2019 situation appears to be:
The calls to the getenv function retrieve the values from a block the MS CRT initializes at load time.
Calls to GetEnvironmentVariable retrieve the value from the process environment block.
Calls to SetEnvironmentVariable update only the value from the process environment block. These changes will not be seen by getenv.
Calls to putenv update both the value in the CRT block and also additionally call Win32 SetEnvironmentVariable to update the process environment block.
So, actually regardless of what you use it for:
Use _wputenv_s to set the env var - it will update both.
Use ::GetEnvironmentVariableW to read: It will read from the environment block, which will contain the value regardless of which method was used.
Regarding getenv
If the code using getenv is using the same MS CRT that your code -- that is, the code is dynamically linked to the CRT and actually uses the same version as you, then you can always use putenv.
If the DLL (AND its CRT) is dynamically or delay-loaded and you are able to call putenv before the dll is loaded, then you can use it.
(This is conjecture, I have not tested this exactly:) If the DLL is already loaded in you process and it uses a statically linked CRT, or another CRT than the one you are using, than the environment data for its getenv call is already loaded up, an nothing that you do on your side of the DLL boundary will change that. Out of luck in this case I guess.
Ref:
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getenv-wgetenv?view=msvc-170
https://github.com/curl/curl/issues/4774
https://blogs.msmvps.com/senthil/2009/10/13/when-what-you-set-is-not-what-you-get-setenvironmentvariable-and-getenv/
As the question is tagged with Python, the blessed way to manage environment variables in Python is to update the os.environ mapping.
Because the doc for os.putenv() says:
Assignments to items in os.environ are automatically translated into corresponding calls to putenv(); however, calls to putenv() don’t update os.environ, so it is actually preferable to assign to items of os.environ.

Categories

Resources