Quick tip: Using Python’s expandvars() with quoted variables on Windows

I recently encountered an elusive bug, which eventually I tracked down to the fact that environment variables are not replaced in a certain string even though it is set by calling os.path.expandvars(original string).

Turns out, the problem is that expandvars() doesn’t expand variables who are enclosed within a string literal. I couldn’t find it documented anywhere but facts are, this is the case.

Small example:

>>> import os
>>> os.environ['VAR1'] = 'Value1'
>>> s1 = "this is '%VAR1%'"
>>> os.path.expandvars(s1)
"this is '%VAR1%'"
>>> s2 = "this is %VAR1%"
>>> os.path.expandvars(s2)
'this is Value1'

It may be a good idea in some cases, but for me it was quite an annoyance.

So, how to overcome this?

Continue reading

Advertisements

Updating Windows Environment Variables

A well-known fact is that, in order to permanently set/modify an environment variable, one should update the Registry under:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment (System Variable)

or

HKEY_CURRENT_USER\Environment (User Variable)

However, this update does not go into effect until logging off and back on.

The solution is to broadcast a Windows Message to all running applications. The following C++ code provides the details:

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);

In Perl, you can simply use the AdminMisc module to set environment variables. If you prefer to stick to standard modules (perl 5.8.9 and later), you can use the following code fragment:

use Win32::API;

	use constant HWND_BROADCAST => -1;
	use constant WM_SETTINGCHANGE => 0x1a;

	my $SendMessage = new Win32::API("user32", "SendMessage",
'NNNP', 'N')
    	or die "Couldn't create SendMessage: $!\n";
	my $RetVal =
$SendMessage->Call(HWND_BROADCAST,WM_SETTINGCHANGE,0,'Environment');

Another alternative is to build the aforementioned C++ code into a small exe file, and use this utility anywhere you like.

In any case, note that the environment variable change will not be visible to the calling process. You’ll need to set it internally (for example, using $ENV in Perl) if you need it to be available inside the script.

References: Microsoft KB Article 104011, PerlMonks thread