Python arguments from Windows Shortcut

Dell / LATITUDE D610
June 20, 2010 at 15:45:44
Specs: Microsoft Windows XP Professional, 2.127 GHz / 1015 MB
So I took a break from Windows batch, and
picked up on some python. I created a script
that runs correctly from a command line. I
created a shortcut to the .py file in my SendTo
folder. Now when I right-click on a file >
SendTo >, it acts like nothing is
being passed to it.

from   optparse  import OptionParser
import win32file
import sys
import os.path
import tkFileDialog

parser = OptionParser()
parser.add_option("-s", "--source", 
dest="source", help="Source file to be HardLinked")
parser.add_option("-t", "--target", dest="target")
(options, args) = parser.parse_args()

if options.source:
    if os.path.isfile(options.source):
        source = options.source
    source = os.path.normpath(tkFileDialog.askopenfilename(title="Select source file to be HardLinked"))
(source_path, source_file) = os.path.split(source)

    if os.path.isdir(
        target =
    target_path = os.path.normpath(tkFileDialog.askdirectory(initialdir=source_path, title="Select Folder to contain HardLinked File"))
target = os.path.join(target_path, source_file)

def output(message):
	sys.stdout.write(message + "\n")

def error(message):
	sys.stderr.write("Error: " + message + "\n")

def Hardlink(source, target):
        win32file.CreateHardLink(target, source)
        if os.path.exists(target):
            output("Successfully created Hardlink for " + source)
        (err_type, err_value, err_traceback) = sys.exc_info()[1]

Hardlink(source, target)

Where is %1? I've modified the shortcut
properties to include: -s %1, and -s

but still no joy. Any ideas?

Insomniac at large

See More: Python arguments from Windows Shortcut

Report •

June 20, 2010 at 16:39:00
What's your file association for the .py extension? Perhaps try
using this as the shortcut command:

python -s %1

By the way, there is a very nice utility you could try instead of
this Python script. It's called Link Shell Extension. I use it myself.

Report •

June 20, 2010 at 17:01:53
Thanks klint, but still no love with calling the interpreter first. Also, the shortcut works, but doesn't accept the passed argument(s).

21:58:37>ftype |find "python"
Python.CompiledFile="C:\Python26\python.exe" "%1" %*
Python.File="C:\Python26\python.exe" "%1" %*"
Python.NoConFile="C:\Python26\pythonw.exe" "%1" %*

21:59:33>assoc .py

22:24:18>set pathext

 22:27:56>reg query HKCR\Python.file\shell\open\command


    <NO NAME>   REG_SZ  "C:\Python26\python.exe" "%1" %*

 22:28:53>reg query HKCR\Applications\Python.exe\shell\open\command


    <NO NAME>   REG_SZ  "C:\Python26\python.exe" "%1" %*

edit: added relative information above.

Insomniac at large

Report •

June 20, 2010 at 20:38:44
What do you get if you:

print sys.argv

Just after the imports?

Edit: I mean specifically when you pass options.

Report •

Related Solutions

June 20, 2010 at 23:24:17
Hi Judago,
Invoking (with print sys.argv) from the shortcut
results in this:
['C:\\path\\', 'C:\\path\\']

which shows it's completely omitting the "-s" prior the
filename. It was a poor choice on my part to select as the source the same file I was invoking.

Well, I see now why I'm always prompted for a
"source" file. It makes no sense to me why python is skipping
over that. I've written a few Windows Batch files that accepts
stuff from a shortcut's target line. I REALLY didn't want to
write a batch wrapper around this...

Insomniac at large

Report •

June 21, 2010 at 01:06:16
I haven't used OptionParser() but my guess would be it doesn't like unspecified options.

Using "send to" is a fundamental problem because you can't intuitively separate source and target. In fact it only makes sense if *every* argument is a source because by nature they will *all* be pre-existing files or directories. This means you will always be forced to prompt for a destination.

If you really want support both the command line and send to you will probably need to adjust the ways it will accept input. Here is my interpretation:

[1] If defined OptionParser() arguments are in use, use them.
[2] if no defined OptionParser() arguments are in use:
    [i] Check that sys.argv contains file names that exist.
    [ii] Problem: Assume that they are all sources(probably
         with a confirm option)
    [iii] Process sys.argv and ask for appropriate targets.

Just be aware I haven't studied your source very closely, so the finer points may elude me.

I forgot to mention that it looks like there could be possible(but rare) issues because all characters used in the option string are legal file name chars.

I'm probably wrong, but it might be interesting to see what a file named "-s" would do.......

Report •

June 21, 2010 at 06:07:11
Thanks Judago,
It's probably a good thing you didn't study the source closely,
because it has a few bugs in it as posted! I had assumed that
os.path.isfile() would check whether the file existed, but it
doesn't, so I had to add a couple if os.path.exists()
statements. Also it seems that every if needs an else (in this
instance at least) to properly prompt for a filename or
directory. Live and learn, I guess!

Concerning OptionParser(), from what I've read, unused options are acceptable
and expected, and helps designate "options" (by definition
optional params), from actual "arguments" (or required
params). I was hoping that OptionParser() would be easier
than getopt(), because I was having problems with "index out
of range" when no filename was passed. It seemed
OptionParser() would fit perfectly for my needs (using the py
script from the command line with no options, with source
being supplied, and the rarer case, because I don't like to
type, with target also being supplied).

I'm wondering now if -s is actually being used implicitly by
python.exe? Unfortunately, both -s and -t are valid arguments
for that interpreter:

 8:55:21>c:\python26\python.exe -h
usage: c:\python26\python.exe [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
-B     : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
-c cmd : program passed in as string (terminates option list)
-d     : debug output from parser; also PYTHONDEBUG=x
-E     : ignore PYTHON* environment variables (such as PYTHONPATH)
-h     : print this help message and exit (also --help)
-i     : inspect interactively after running script; forces a prompt even
         if stdin does not appear to be a terminal; also PYTHONINSPECT=x
-m mod : run library module as a script (terminates option list)
-O     : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x
-OO    : remove doc-strings in addition to the -O optimizations
-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew
-s     : don't add user site directory to sys.path; also PYTHONNOUSERSITE
-S     : don't imply 'import site' on initialization
-t     : issue warnings about inconsistent tab usage (-tt: issue errors)
-u     : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
         see man page for details on internal buffering relating to '-u'
-v     : verbose (trace import statements); also PYTHONVERBOSE=x
         can be supplied multiple times to increase verbosity
-V     : print the Python version number and exit (also --version)
-W arg : warning control; arg is action:message:category:module:lineno
-x     : skip first line of source, allowing use of non-Unix forms of #!cmd
-3     : warn about Python 3.x incompatibilities that 2to3 cannot trivially fix
file   : program read from script file
-      : program read from stdin (default; interactive mode if a tty)
arg ...: arguments passed to program in sys.argv[1:]

Other environment variables:
PYTHONSTARTUP: file executed on interactive startup (no default)
PYTHONPATH   : ';'-separated list of directories prefixed to the
               default module search path.  The result is sys.path.
PYTHONHOME   : alternate <prefix> directory (or <prefix>;<exec_prefix>).
               The default module search path uses <prefix>\lib.
PYTHONCASEOK : ignore case in 'import' statements (Windows).
PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.

But I think if that were the case, I'd have to have -s or -t
before my script name at invocation. I'll keep beating
up on it to see if it will do what I want. :-)

Thanks again!

Insomniac at large

Report •

June 21, 2010 at 11:41:25
Wrote this:

SET /A token_counter=1
FOR /F "tokens=%token_counter% delims= " %%a IN ("%*") DO (
    ECHO %%%token_counter% = %%a
    SET /A token_counter+=1
    GOTO Token_loop


Outputs this:

%1 = -s
%2 = 5
%3 = 4
%4 = 3
%5 = 2
Press any key to continue . . .

when the shortcut has this as it's target:
"\\Dl380-server\lan path\test.bat" -s 5 4 3 2

So I don't think it's a Windows shortcut problem. Like the tree said to the lumberjack: "I'm stumped." :-/

Insomniac at large

Report •

June 21, 2010 at 15:07:51
Indeed, any option that's part of the shortcut does seem to disappear(I also tried -x). The only workaround I can see is to allow positional arguments, which in itself voids the concept of the option parser......

Report •

June 21, 2010 at 17:11:44
Thanks for confirming Judago. All I can say is Arrrgh! ;-)

Insomniac at large

Report •

Ask Question