maintain 2 versions of python on my computer

L

luis

Hi

I am not an expert in programming and using Python for its simplicity

I have 2 versions of python installed on my computer (windos xp) to
begin the transition from version 2.4 to 2.6 or 3. maintaining the
operability of my old scripts

Is there any way to indicate the version of the python interpreter
must use a script?

thanks
 
A

Alf P. Steinbach

* luis:
Hi

I am not an expert in programming and using Python for its simplicity

I have 2 versions of python installed on my computer (windos xp) to
begin the transition from version 2.4 to 2.6 or 3. maintaining the
operability of my old scripts

Is there any way to indicate the version of the python interpreter
must use a script?

I think the most direct way is to use different filename extensions, and
associate them with corresponding interpreters via the 'assoc' and 'ftype'
Windows commands.

An alternative is to associate '.py' and '.pyw' with two dummy programs (console
and GUI subsystem programs) that in some way determines the Python version of
the script and invokes the right interpreter.

Offhand I can think of three ways to let such a dummy program know the Python
version of a script (filename extensions are not a way because with distinct
filename extensions you don't need the dummy program):

* version information in comment in the file.

* version information in the filename, like e.g. 'myscript.python31.py',
or version information in the general path, e.g. 'python31\myscript.py'.

* version information in some kind of 'database', which might be a
separate file or simply hardcoded in your dummy startup program.

But I think personally I'd go for filename extensions and using 'assoc' and
'ftype', because while ugly it's simplest, like '.py24', '.py26', 'py31'.


Cheers & hth.,

- Alf
 
G

Gabriel Genellina

I am not an expert in programming and using Python for its simplicity

I have 2 versions of python installed on my computer (windos xp) to
begin the transition from version 2.4 to 2.6 or 3. maintaining the
operability of my old scripts

Is there any way to indicate the version of the python interpreter
must use a script?

See http://www.effbot.org/zone/exemaker.htm
It uses the #! line to determine which version to load, resembling the
Unix way.
(I've written a variant of the same idea but isn't ready yet)

Or, you can always invoke your scripts with an explicit interpreter.
Create a python24.cmd file containing just this line:

@c:\path\to\python.exe %*

(and a similar one for 2.6 and 3.0) and put them somewhere in your path
(it is convenient to add a single directory to the system PATH for your
own utilities; I use c:\util; others use c:\bin).

Then you can say:

python26 foo.py

to execute foo.py using Python 2.6
 
R

r0g

luis said:
Hi

I am not an expert in programming and using Python for its simplicity

I have 2 versions of python installed on my computer (windos xp) to
begin the transition from version 2.4 to 2.6 or 3. maintaining the
operability of my old scripts

Is there any way to indicate the version of the python interpreter
must use a script?

thanks


On unix you would start the file with a "hashbang" e.g.

#!/usr/bin/python3

Fraid I don't know if that works on XP though.

Roger.
 
L

Lie Ryan

Hi

I am not an expert in programming and using Python for its simplicity

I have 2 versions of python installed on my computer (windos xp) to
begin the transition from version 2.4 to 2.6 or 3. maintaining the
operability of my old scripts

Is there any way to indicate the version of the python interpreter
must use a script?

thanks

On my Windows machine, I make a copy python.exe and rename it as
python25.exe, python26.exe, python3.exe, etc in their respective
directories. Then after setting up the PATH environment variable, you
can simply call python25, python3, etc from any directory in the command
prompt.

Tips: On Vista and above, you can Shift-Right-Click to show "Open
Command Window Here" in the context menu. On XP, you can install the
PowerToys
http://www.microsoft.com/windowsxp/Downloads/powertoys/Xppowertoys.mspx
 
G

Gertjan Klein

Gabriel said:
See http://www.effbot.org/zone/exemaker.htm
It uses the #! line to determine which version to load, resembling the
Unix way.
(I've written a variant of the same idea but isn't ready yet)

I'd be interested to see what you've come up with, if you care to share.
I've been thinking about something like this as well. Exemaker, for me,
is the wrong solution, because it requires making an .exe file for every
script you want to run this way.

What I've been thinking about is to write a single executable that gets
associated with .py and .pyw (instead of python.exe itself). This
executable would parse the #! line to look for a specific python
version, or use a configured default if none found (or a parsing error
occurs). It would then invoke the appropriate python version (with
whatever arguments, if any, are supplied).

As far as I can see, this allows both typing the script name and
arguments (i.e., without python31 before it) from a command prompt, and
doubleclicking on a .py or .pyw file from windows explorer. In both
cases, the proper python executable would be used to run the script.

What's been holding me back so far is that probably needs to be written
in C, to prevent the Python runtime's startup overhead. I haven't
written any significant amount of C code in years, if not decades, so
that seems like a daunting task to me at the moment. ;-)

Gertjan.
 
A

Alf P. Steinbach

* Gertjan Klein:
What I've been thinking about is to write a single [Windows] executable that
gets associated with .py and .pyw (instead of python.exe itself).

Well, you need two: one for console subsystem, and one for GUI subsystem.

Happily you can use the same source code. :)

This
executable would parse the #! line to look for a specific python
version, or use a configured default if none found (or a parsing error
occurs). It would then invoke the appropriate python version (with
whatever arguments, if any, are supplied).

As far as I can see, this allows both typing the script name and
arguments (i.e., without python31 before it) from a command prompt, and
doubleclicking on a .py or .pyw file from windows explorer. In both
cases, the proper python executable would be used to run the script.

What's been holding me back so far is that probably needs to be written
in C, to prevent the Python runtime's startup overhead. I haven't
written any significant amount of C code in years, if not decades, so
that seems like a daunting task to me at the moment. ;-)

If it's OK with C++, I just sat down and wrote this.

It's not especially well tested (or almost not at all), and it's limited.

It handles or is meant to handle Unicode script file paths, but the path to the
Python interpreter, specified in a "#!" comment in the script's first line, must
be single byte per character. And if that path contains spaces must be quoted.


<code file="run_script.cpp">
// Note: in order to handle Unicode paths needs to use Windows API command line.
//
// If this code works then it was written (but not tested) by Alf P. Steinbach.
// Otherwise it's someone impersonating me.

#include <string> // std::wstring
#include <vector> // std::vector
#include <stdexcept>
#include <stdio.h>
#include <stddef.h>

#undef STRICT
#undef NOMINMAX
#undef UNICODE
#define STRICT
#define NOMINMAX
#define UNICODE
#include <windows.h> // CommandLineToArgvW, GetCommandLine

using namespace std;


//------------------------------ Various things ordinarily from libraries...

bool throwX( char const s[] ) { throw std::runtime_error( s ); }

typedef ptrdiff_t Size;

template< typename Container >
Size n_elements( Container const& c ) { return c.size(); }

// The C++98 standard library doesn't offer Unicode filename functionality.
// Using library extension that works with GNU g++ and Microsoft Visual C++.
class TextFileReader
{
private:
FILE* f;
TextFileReader( TextFileReader const& ); // No copy constructor.
TextFileReader& operator=( TextFileReader const& ); // No assignment.

public:
TextFileReader( wstring const& path )
: f( _wfopen( path.c_str(), L"r" ) )
{
(f != 0) || throwX( "Unable to open file for reading" );
}

~TextFileReader() { fclose( f ); }

wstring line()
{
wstring s;
for( ;; )
{
int const c = fgetc( f );
if( c == EOF || c == L'\n' ) { break; }
s.push_back( wchar_t( c ) );
}
return s;
}
};

wstring substring( wstring const& s, Size const i, Size const n = -1 )
{
wstring::size_type const count = (n == -1? wstring::npos : n);
return (i >= n_elements( s )? L"" : s.substr( i, count ));
}

//------------------------------ Main

typedef wstring String;
typedef vector<String> StringVector;


StringVector cmdArguments()
{
struct Args
{
wchar_t** p;
int n;

Args()
{
p = CommandLineToArgvW( GetCommandLine(), &n );
(p != 0) || throwX( "Unable to obtain command line arguments" );
}

~Args() { GlobalFree( p ); }
};

Args const args;
return StringVector( args.p, args.p + args.n );
}

int run( wstring const& prog_path, wstring const& args )
{
wstring cmd_line = prog_path + L" " + args;

cmd_line.c_str();
PROCESS_INFORMATION process_info = {};
STARTUPINFO startup_info = { sizeof( startup_info ) };
bool const ok = !!CreateProcess(
0, // application name
&cmd_line[0], // command line
0, // process security attributes
0, // thread security attributes
TRUE, // inherit handles
0, // creation flags
0, // environment, 0 => inherit parent process env.
0, // current directory
&startup_info,
&process_info
);
(ok)
|| throwX( "Unable to run the interpreter" );


bool const wait_ok =
(WaitForSingleObject( process_info.hProcess, INFINITE ) != WAIT_FAILED);

DWORD exit_code = EXIT_FAILURE;
GetExitCodeProcess( process_info.hProcess, &exit_code );
CloseHandle( process_info.hProcess );
CloseHandle( process_info.hThread );

(wait_ok) || throwX( "Waiting for the program to end failed" );
return exit_code;
}

int cppMain()
{
StringVector const args = cmdArguments();
(n_elements( args ) == 2)
|| throwX( "Usage: run_script QUOTED_PATH_TO_SCRIPT_FILE" );

wstring const script_path = args[1];
wstring const first_line = TextFileReader( script_path ).line();
wstring const prefix = substring( first_line, 0, 2 );
wstring const prog_path = substring( first_line, 2 );
(prefix == L"#!" && prog_path.length() > 0)
|| throwX( "Unable to determine interpreter" );

return run( prog_path, script_path );
}

int main()
{
try
{
return cppMain();
}
catch( exception const& x )
{
fprintf( stderr, "!run_script: %s\n", x.what() );
return EXIT_FAILURE;
}
}
<code>


<build compiler="g++">
g++ -std=c++98 -pedantic run_script.cpp -o run_script.exe
g++ -std=c++98 -pedantic run_script.cpp -Wl,-subsystem,windows -o run_scriptw.exe
</build>


<build compiler="msvc">
cl /nologo /GX /GR run_script.cpp shell32.lib
cl /nologo /GX /GR run_script.cpp shell32.lib /Fe:run_scriptw.exe /link
/subsystem:windows /entry:mainCRTStartup
run_script.cpp
</build>


<code file="test.py">
#!python

print( "Hello" )
exit( 123 )
</code>



Cheers & hth.,

- Alf
 
G

Gertjan Klein

Alf said:
* Gertjan Klein:
What I've been thinking about is to write a single [Windows] executable that
gets associated with .py and .pyw (instead of python.exe itself).

Well, you need two: one for console subsystem, and one for GUI subsystem.

Why? I'd have imagined writing something for the GUI subsystem (without
actually creating a GUI, just to prevent a DOS box popping up), creating
the proper commandline, with either python.exe or pythonw.exe, and
launching that as a separate process. (I have no idea whether this would
actually work though -- I'm just thinking out loud at this stage.)

Thinking about it some more, perhaps that way I can't get at return
codes a python script might provide. I haven't used those, but they may
be useful at some point.
If it's OK with C++, I just sat down and wrote this.

Thanks for that. I won't be using it though; I don't know C++ at all,
and the source looks like complete gobbledygook to me. I wouldn't know
where to begin to change anything in it. ;-)

Gertjan.
 
A

Alf P. Steinbach

* Gertjan Klein:
Alf said:
* Gertjan Klein:
What I've been thinking about is to write a single [Windows] executable that
gets associated with .py and .pyw (instead of python.exe itself).
Well, you need two: one for console subsystem, and one for GUI subsystem.

Why? I'd have imagined writing something for the GUI subsystem (without
actually creating a GUI, just to prevent a DOS box popping up), creating
the proper commandline, with either python.exe or pythonw.exe, and
launching that as a separate process. (I have no idea whether this would
actually work though -- I'm just thinking out loud at this stage.)

Thinking about it some more, perhaps that way I can't get at return
codes a python script might provide. I haven't used those, but they may
be useful at some point.

Return codes work OK no matter what.

But it's a hassle for the user to connect up standard input, standard output and
standard error for a GUI subsystem process.

That's mainly why the distinction between [.py] and [.pyw] is there in Windows:
the former is associated with console subsystem interpreter ensuring that the
standard streams are connected up automatically, the latter is associated with
GUI subsystem interpreter ensuring no automatic console window.

Thanks for that. I won't be using it though; I don't know C++ at all,
and the source looks like complete gobbledygook to me. I wouldn't know
where to begin to change anything in it. ;-)

Ah, well.

Perhaps do this in JScript or VBScript (languages bundled with Windows)? There
may be less startup overhead than with Python. But I haven't checked.



Cheers,

- Alf
 
G

Gertjan Klein

Alf said:
* Gertjan Klein:

Return codes work OK no matter what.

Ok, I won't have to worry about that then. ;-)
But it's a hassle for the user to connect up standard input, standard output and
standard error for a GUI subsystem process.

Good point. Two executables it is. But out of curiousity, what happens
when a user pipes something into a GUI subsystem executable?
Perhaps do this in JScript or VBScript (languages bundled with Windows)? There
may be less startup overhead than with Python. But I haven't checked.

Won't these create a DOS window, always? Or can they run windowless as
well? If so, that might be an option worth exploring as well.

Gertjan.
 
M

Mike

On unix you would start the file with a "hashbang" e.g.
#!/usr/bin/python3

Fraid I don't know if that works on XP though.

Roger.

It does not; Windows associates applications with file extensions.
However, I have used something like this to get something like the
Unix shebang behavior:

@echo off
rem = """ ver26.bat: Python 2.6
C:\Python26\python -x %~f0 %*
goto END
rem """
# ver26.py wrapped in ver26.bat to mimic Unix #! behavior

import sys
print sys.version

rem = """
:END
pause
rem """

@echo off
rem = """ ver31.bat: Python 3.1
D:\Python31\python -x %~f0 %*
goto END
rem """
# ver31.py wrapped in ver31.bat to mimic Unix #! behavior

import sys
print(sys.version)

rem = """
:END
pause
rem """

I cannot remember where I first saw this, and don't think I have ever
seen it since. It seems like a bit of a hack, but I use it from time
to time when I cannot rely on Windows file associations. Perl has
a much cleaner way to accomplish the same thing for Windows (see the
pl2bat.bat script that ships with
Perl Windows distributions).

Mike
 
M

Mike

That seems overkill. This does pretty much the same thing:
        @(C:\Python26\Python -x %~f0 %* || pause) && goto:EOF
        import sys
        print sys.version
        # raise RuntimeError # uncomment to trigger the 'pause'

Indeed! Must be as close to a "Windows shebang line" as you can get.

In actual use, if/when I want a pause, I typically make a call
raw_input() or msvcrt.getch()
EOF is a special label which may be used to exist a CMD file without having
to explicitly define it.

Did not know that; something new for my toolbox!

Mike
 
A

Alf P. Steinbach

* Gertjan Klein:
Ok, I won't have to worry about that then. ;-)


Good point. Two executables it is. But out of curiousity, what happens
when a user pipes something into a GUI subsystem executable?

The same as with a console program, I guess.

Indeed piping is one way to connect up the output.

Disclaimer: I can't recall ever actually trying to pipe input to a GUI subsystem
exe. However, piping output, while not common, at least I've done that! :)

Won't these create a DOS window, always?

No. They're run via the Windows Script Host interface. WSH has two runner
programs: cscript (console) and wscript (GUI). So you get a console window (it's
tehnically not DOS although the icon was MS-DOS until and including Windows NT
4.0) if you run a [.js] or [.vbs] file via cscript, and not via wscript.

wscript is the default.

But you can change that association, or create new associations, via the Windows
'assoc' and 'ftype' commands (note that after some XP update 'ftype' is no
longer able to delete associations, it must then be done directly in registry).

Or can they run windowless as well?

Yes, see above.

If so, that might be an option worth exploring as well.



Cheers & hth.,

- Alf
 
G

Gabriel Genellina

I'd be interested to see what you've come up with, if you care to share.
I've been thinking about something like this as well. Exemaker, for me,
is the wrong solution, because it requires making an .exe file for every
script you want to run this way.

The advantage is that Task Manager shows the right program name, instead
of always "python.exe". (You don't have to *make* an .exe for every
script, just rename/copy it.)
If you don't care, the recipe posted by Duncan Booth is as close as a #!
line as its gets.
 
S

Sridhar Ratnakumar

On my Windows machine, I make a copy python.exe and rename it as
python25.exe, python26.exe, python3.exe, etc in their respective
directories. Then after setting up the PATH environment variable, you
can simply call python25, python3, etc from any directory in the command
prompt.

Lie, ActivePython does both of this during the installation --
pythonXY.exe and set PATH accordingly.

Luis, Distribute (a setuptools fork) has a feature called "entry points"
that will create exe wrappers for the specified Python script. These exe
wrappers use the #! line to determine the actual Python interpreter to
invoke.


http://packages.python.org/distribute/setuptools.html#automatic-script-creation

If your script is foo-script.py, foo.exe will ultimately read the first
line in foo-script.py which is #!C:\Python26\python.exe .. and that is
used to run the script. Task manager will show "foo.exe" instead of
"python.exe".

-srid
 
A

Aahz

That seems overkill. This does pretty much the same thing:

@(C:\Python26\Python -x %~f0 %* || pause) && goto:EOF
import sys
print sys.version
# raise RuntimeError # uncomment to trigger the 'pause'

<blink> What version of Windows is necessary to use this? Anything with
cmd.exe? (Sure doesn't look anything like DOS batch files...)
 
A

Alf P. Steinbach

* Aahz:
<blink> What version of Windows is necessary to use this? Anything with
cmd.exe? (Sure doesn't look anything like DOS batch files...)

Well, all of that has been there since, I don't know, long ago...

-x A Python option that skips the first line of the script.
@ suppresses echo of the line.
() group commands (creates a compound command)
|| shortcut-evaluated OR
&& shortcut-evaluated AND
% see below...


C:\test> for /? | find "%~"
%~I - expands %I removing any surrounding quotes (")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path contains short names only
%~aI - expands %I to file attributes of file
%~tI - expands %I to date/time of file
%~zI - expands %I to size of file
%~$PATH:I - searches the directories listed in the PATH
%~dpI - expands %I to a drive letter and path only
%~nxI - expands %I to a file name and extension only
%~fsI - expands %I to a full path name with short names only
%~dp$PATH:I - searches the directories listed in the PATH
%~ftzaI - expands %I to a DIR like output line
values. The %~ syntax is terminated by a valid FOR variable name.

C:\test> _

Cheers & hth. (even if a bit off-topic!),


- Alf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top