[GRASS-SVN] r57910 - in grass/trunk: gui/wxpython/core lib/python/script
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Oct 1 19:55:55 PDT 2013
Author: wenzeslaus
Date: 2013-10-01 19:55:55 -0700 (Tue, 01 Oct 2013)
New Revision: 57910
Modified:
grass/trunk/gui/wxpython/core/gcmd.py
grass/trunk/lib/python/script/core.py
grass/trunk/lib/python/script/task.py
Log:
handling of scripts on MS Win using Python which (uses PATH) and sys.executable (for grass.script and wxGUI), fixes MAXREPEAT error when running Python script
Modified: grass/trunk/gui/wxpython/core/gcmd.py
===================================================================
--- grass/trunk/gui/wxpython/core/gcmd.py 2013-10-01 18:32:00 UTC (rev 57909)
+++ grass/trunk/gui/wxpython/core/gcmd.py 2013-10-02 02:55:55 UTC (rev 57910)
@@ -533,16 +533,21 @@
self.startTime = time.time()
# TODO: replace ugly hack below
+ # this cannot be replaced it can be only improved
+ # also unifying this with 3 other places in code would be nice
+ # changing from one chdir to get_real_command function
args = self.cmd
if sys.platform == 'win32':
- ext = os.path.splitext(self.cmd[0])[1] == globalvar.SCT_EXT
- if ext or self.cmd[0] in globalvar.grassScripts[globalvar.SCT_EXT]:
- os.chdir(os.path.join(os.getenv('GISBASE'), 'scripts'))
- if not ext:
- args = [sys.executable, self.cmd[0] + globalvar.SCT_EXT] + self.cmd[1:]
- else:
- args = [sys.executable, self.cmd[0]] + self.cmd[1:]
-
+ if os.path.splitext(args[0])[1] == globalvar.SCT_EXT:
+ args[0] = args[0][:-3]
+ # using Python executable to run the module if it is a script
+ # expecting at least module name at first position
+ # cannot use make_command for this now because it is used in GUI
+ # The same code is in grass.script.core already twice.
+ args[0] = grass.get_real_command(args[0])
+ if args[0].endswith('.py'):
+ args.insert(0, sys.executable)
+
try:
self.module = Popen(args,
stdin = subprocess.PIPE,
Modified: grass/trunk/lib/python/script/core.py
===================================================================
--- grass/trunk/lib/python/script/core.py 2013-10-01 18:32:00 UTC (rev 57909)
+++ grass/trunk/lib/python/script/core.py 2013-10-02 02:55:55 UTC (rev 57910)
@@ -144,6 +144,112 @@
return set(cmd), scripts
+# replacement for which function from shutil (not available in all versions)
+# from http://hg.python.org/cpython/file/6860263c05b3/Lib/shutil.py#l1068
+# added because of Python scripts running Python scripts on MS Windows
+# see also ticket #2008 which is unrelated but same function was proposed
+def shutil_which(cmd, mode=os.F_OK | os.X_OK, path=None):
+ """Given a command, mode, and a PATH string, return the path which
+ conforms to the given mode on the PATH, or None if there is no such
+ file.
+
+ `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
+ of os.environ.get("PATH"), or can be overridden with a custom search
+ path.
+
+ """
+ # Check that a given file can be accessed with the correct mode.
+ # Additionally check that `file` is not a directory, as on Windows
+ # directories pass the os.access check.
+ def _access_check(fn, mode):
+ return (os.path.exists(fn) and os.access(fn, mode)
+ and not os.path.isdir(fn))
+
+ # If we're given a path with a directory part, look it up directly rather
+ # than referring to PATH directories. This includes checking relative to the
+ # current directory, e.g. ./script
+ if os.path.dirname(cmd):
+ if _access_check(cmd, mode):
+ return cmd
+ return None
+
+ if path is None:
+ path = os.environ.get("PATH", os.defpath)
+ if not path:
+ return None
+ path = path.split(os.pathsep)
+
+ if sys.platform == "win32":
+ # The current directory takes precedence on Windows.
+ if not os.curdir in path:
+ path.insert(0, os.curdir)
+
+ # PATHEXT is necessary to check on Windows.
+ pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
+ # See if the given file matches any of the expected path extensions.
+ # This will allow us to short circuit when given "python.exe".
+ # If it does match, only test that one, otherwise we have to try
+ # others.
+ if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
+ files = [cmd]
+ else:
+ files = [cmd + ext for ext in pathext]
+ else:
+ # On other platforms you don't have things like PATHEXT to tell you
+ # what file suffixes are executable, so just pass on cmd as-is.
+ files = [cmd]
+
+ seen = set()
+ for dir in path:
+ normdir = os.path.normcase(dir)
+ if not normdir in seen:
+ seen.add(normdir)
+ for thefile in files:
+ name = os.path.join(dir, thefile)
+ if _access_check(name, mode):
+ return name
+ return None
+
+
+# Added because of scripts calling scripts on MS Windows.
+# Module name (here cmd) differs from the file name (does not have extension).
+# Additionally, we don't run scripts using system executable mechanism,
+# so we need the full path name.
+# However, scripts are on the PATH and '.PY' in in PATHEXT, so we can use
+# shutil.which to get the full file path. Addons are on PATH too.
+# An alternative to which function call would be to check the script path and
+# addons path. This is proposed improvement for the future.
+# Another alternative is to check some global list of scripts but this list
+# needs to be created first. The question is what is less expensive.
+# Note that getting the full path is only part of the solution,
+# the other part is to use the right Python as an executable and pass the full
+# script path as a parameter.
+# Nevertheless, it is unclear on which places which extensions are added.
+# This function also could skip the check for platform but depends
+# how will be used, this is most general but not most effective.
+def get_real_command(cmd):
+ """!Returns the real file commad for a module (cmd)
+
+ For Python scripts on MS Windows it returns full path to the script
+ and adds a '.py' extension.
+ For other cases it just returns a module (name).
+ So, you can just use this function for all without further check.
+
+ >>> get_real_command('g.region')
+ 'g.region'
+ """
+ if sys.platform == 'win32':
+ # we in fact expect pure module name (without extension)
+ # so, lets remove extension
+ if os.path.splitext(cmd)[1] == '.py':
+ cmd = cmd[:-3]
+ full_path = shutil_which(cmd + '.py')
+ if full_path:
+ return full_path
+
+ return cmd
+
+
def make_command(prog, flags="", overwrite=False, quiet=False, verbose=False,
**options):
"""!Return a list of strings suitable for use as the args parameter to
@@ -221,6 +327,13 @@
options[opt] = val
args = make_command(prog, flags, overwrite, quiet, verbose, **options)
+ # using Python executable to run the module if it is a script
+ # expecting at least module name at first position
+ # cannot use make_command for this now because it is used in GUI
+ if sys.platform == "win32":
+ args[0] = get_real_command(args[0])
+ if args[0].endswith('.py'):
+ args.insert(0, sys.executable)
if debug_level() > 0:
sys.stderr.write("D1/%d: %s.start_command(): %s\n" % (debug_level(),
@@ -370,6 +483,14 @@
"""
args = make_command(prog, flags, overwrite, quiet, verbose, **kwargs)
+ # using Python executable to run the module if it is a script
+ # expecting at least module name at first position
+ # cannot use make_command for this now because it is used in GUI
+ if sys.platform == "win32":
+ args[0] = get_real_command(args[0])
+ if args[0].endswith('.py'):
+ args.insert(0, sys.executable)
+
if env == None:
env = os.environ
os.execvpe(prog, args, env)
Modified: grass/trunk/lib/python/script/task.py
===================================================================
--- grass/trunk/lib/python/script/task.py 2013-10-01 18:32:00 UTC (rev 57909)
+++ grass/trunk/lib/python/script/task.py 2013-10-02 02:55:55 UTC (rev 57910)
@@ -466,14 +466,17 @@
cmdout, cmderr = p.communicate()
# TODO: replace ugly hack bellow
+ # expecting that cmd is without .py
if not cmdout and sys.platform == 'win32':
- if os.path.splitext(cmd)[1] != '.py':
+ # we in fact expect pure module name (without extension)
+ # so, lets remove extension
+ if os.path.splitext(cmd)[1] == '.py':
+ cmd = cmd[:-3]
+ if cmd == 'd.rast3d':
cmd += '.py'
-
- if cmd == 'd.rast3d.py':
os.chdir(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'scripts'))
else:
- os.chdir(os.path.join(os.getenv('GISBASE'), 'scripts'))
+ cmd = get_real_command(cmd)
p = Popen([sys.executable, cmd, '--interface-description'],
stdout = PIPE, stderr = PIPE)
cmdout, cmderr = p.communicate()
More information about the grass-commit
mailing list