Skip to content

Commit

Permalink
grass.script: Remove shutil.which replacement and Python 2/3 unicode (O…
Browse files Browse the repository at this point in the history
…SGeo#2366)

- Remove shutil.which replacement for Python 2.
- Remove unicode alias for Python 3.
  • Loading branch information
wenzeslaus authored and ninsbl committed Feb 17, 2023
1 parent c03a908 commit f3bc923
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 136 deletions.
5 changes: 3 additions & 2 deletions python/grass/gunittest/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from __future__ import print_function

import os
import shutil
import subprocess
import sys
import hashlib
Expand All @@ -19,7 +20,7 @@

from grass.pygrass.modules import Module
from grass.exceptions import CalledModuleError
from grass.script import shutil_which, text_to_string, encode, decode
from grass.script import text_to_string, encode, decode

from .gmodules import call_module, SimpleModule
from .checkers import (
Expand Down Expand Up @@ -1396,7 +1397,7 @@ def assertModule(self, module, msg=None, **kwargs):
"""
module = _module_from_parameters(module, **kwargs)
_check_module_run_parameters(module)
if not shutil_which(module.name):
if not shutil.which(module.name):
stdmsg = "Cannot find the module '{0}'".format(module.name)
self.fail(self._formatMessage(msg, stdmsg))
try:
Expand Down
97 changes: 6 additions & 91 deletions python/grass/script/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@
from .utils import KeyValue, parse_key_val, basename, encode, decode, try_remove
from grass.exceptions import ScriptError, CalledModuleError

# PY2/PY3 compat
if sys.version_info.major >= 3:
unicode = str


# subprocess wrapper that uses shell on Windows
class Popen(subprocess.Popen):
Expand All @@ -54,7 +50,7 @@ def __init__(self, args, **kwargs):
and not kwargs.get("shell", False)
and kwargs.get("executable") is None
):
cmd = shutil_which(args[0])
cmd = shutil.which(args[0])
if cmd is None:
raise OSError(_("Cannot find the executable {0}").format(args[0]))
args = [cmd] + args[1:]
Expand Down Expand Up @@ -97,16 +93,16 @@ def call(*args, **kwargs):


def _make_val(val):
"""Convert value to unicode"""
if isinstance(val, (bytes, str, unicode)):
"""Convert value to a unicode string"""
if isinstance(val, (bytes, str)):
return decode(val)
if isinstance(val, (int, float)):
return unicode(val)
return str(val)
try:
return ",".join(map(_make_val, iter(val)))
except TypeError:
pass
return unicode(val)
return str(val)


def _make_unicode(val, enc):
Expand Down Expand Up @@ -166,87 +162,6 @@ def scan(gisbase, directory):
return set(cmd), scripts


# TODO: Please replace this function with shutil.which() before 8.0 comes out
# 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.
:param cmd: the command
:param mode:
:param 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 os.curdir not in path:
path.insert(0, os.curdir)

# PATHEXT is necessary to check on Windows (force lowercase)
pathext = list(
map(lambda x: x.lower(), os.environ.get("PATHEXT", "").split(os.pathsep))
)
if ".py" not in pathext:
# we assume that PATHEXT contains always '.py'
pathext.insert(0, ".py")
# See if the given file matches any of the expected path extensions.
# This will allow us to short circuit when given "python3.exe".
# If it does match, only test that one, otherwise we have to try
# others.
if any(cmd.lower().endswith(ext) 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 normdir not in seen:
seen.add(normdir)
for thefile in files:
name = os.path.join(dir, thefile)
if _access_check(name, mode):
return name
return None


if sys.version_info.major >= 3:
# Use shutil.which in Python 3, not the custom implementation.
shutil_which = shutil.which # noqa: F811


# 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,
Expand Down Expand Up @@ -288,7 +203,7 @@ def get_real_command(cmd):
if ".py" not in pathext:
# we assume that PATHEXT contains always '.py'
os.environ["PATHEXT"] = ".py;" + os.environ["PATHEXT"]
full_path = shutil_which(cmd + ".py")
full_path = shutil.which(cmd + ".py")
if full_path:
return full_path

Expand Down
32 changes: 16 additions & 16 deletions raster/r.in.pdal/testsuite/test_r_in_pdal_binning.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
import os
import pathlib
import unittest
import shutil
from tempfile import TemporaryDirectory

from grass.script import core as grass
from grass.script import shutil_which
from grass.gunittest.case import TestCase
from grass.gunittest.main import test

Expand All @@ -28,7 +28,7 @@ class BinningTest(TestCase):
"""

@classmethod
@unittest.skipIf(shutil_which("pdal") is None, "Cannot find pdal utility")
@unittest.skipIf(shutil.which("pdal") is None, "Cannot find pdal utility")
def setUpClass(cls):
"""Ensures expected computational region and generated data"""
cls.use_temp_region()
Expand Down Expand Up @@ -62,7 +62,7 @@ def tearDownClass(cls):
cls.tmp_dir.cleanup()
cls.del_temp_region()

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def tearDown(self):
"""Remove the outputs created by the import
Expand All @@ -71,7 +71,7 @@ def tearDown(self):
self.runModule("g.remove", flags="f", type="raster", name=self.bin_raster)
self.runModule("g.remove", flags="f", type="raster", name=self.ref_raster)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_n(self):
"""Test binning with n method"""
self.bin_raster = "bin_n"
Expand All @@ -94,7 +94,7 @@ def test_method_n(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_min(self):
self.bin_raster = "bin_min"
self.ref_raster = "ref_min"
Expand All @@ -116,7 +116,7 @@ def test_method_min(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_max(self):
self.bin_raster = "bin_max"
self.ref_raster = "ref_max"
Expand All @@ -138,7 +138,7 @@ def test_method_max(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_range(self):
self.bin_raster = "bin_range"
self.ref_raster = "ref_range"
Expand All @@ -160,7 +160,7 @@ def test_method_range(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_sum(self):
self.bin_raster = "bin_sum"
self.ref_raster = "ref_sum"
Expand All @@ -182,7 +182,7 @@ def test_method_sum(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_mean(self):
self.bin_raster = "bin_mean"
self.ref_raster = "ref_mean"
Expand All @@ -204,7 +204,7 @@ def test_method_mean(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0.0001)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_stddev(self):
self.bin_raster = "bin_stddev"
self.ref_raster = "ref_stddev"
Expand All @@ -226,7 +226,7 @@ def test_method_stddev(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0.0001)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_variance(self):
self.bin_raster = "bin_variance"
self.ref_raster = "ref_variance"
Expand All @@ -248,7 +248,7 @@ def test_method_variance(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0.0001)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_coeff_var(self):
self.bin_raster = "bin_coeff_var"
self.ref_raster = "ref_coeff_var"
Expand All @@ -270,7 +270,7 @@ def test_method_coeff_var(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0.0001)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_median(self):
self.bin_raster = "bin_median"
self.ref_raster = "ref_median"
Expand All @@ -292,7 +292,7 @@ def test_method_median(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0.0001)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_mode(self):
self.bin_raster = "bin_mode"
self.ref_raster = "ref_mode"
Expand All @@ -314,7 +314,7 @@ def test_method_mode(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_sidnmax(self):
self.bin_raster = "bin_sidnmax"
self.ref_raster = "ref_sidnmax"
Expand All @@ -336,7 +336,7 @@ def test_method_sidnmax(self):
)
self.assertRastersEqual(self.bin_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_method_sidnmin(self):
self.bin_raster = "bin_sidnmin"
self.ref_raster = "ref_sidnmin"
Expand Down
12 changes: 6 additions & 6 deletions raster/r.in.pdal/testsuite/test_r_in_pdal_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@

import os
import pathlib
import shutil
import unittest
from tempfile import TemporaryDirectory

from grass.script import core as grass
from grass.script import shutil_which
from grass.gunittest.case import TestCase
from grass.gunittest.main import test

Expand All @@ -28,7 +28,7 @@ class SelectionTest(TestCase):
"""

@classmethod
@unittest.skipIf(shutil_which("pdal") is None, "Cannot find pdal utility")
@unittest.skipIf(shutil.which("pdal") is None, "Cannot find pdal utility")
def setUpClass(cls):
"""Ensures expected computational region and generated data"""
cls.use_temp_region()
Expand Down Expand Up @@ -74,7 +74,7 @@ def tearDown(self):
except AttributeError:
pass

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_dimension(self):
"""Test LAS dimension selection"""
self.imp_raster = "imp_intensity"
Expand All @@ -99,7 +99,7 @@ def test_dimension(self):
)
self.assertRastersEqual(self.imp_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_user_dimension(self):
"""Test PDAL user dimension selection"""
self.imp_raster = "imp_cellid"
Expand All @@ -124,7 +124,7 @@ def test_user_dimension(self):
)
self.assertRastersEqual(self.imp_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_filter(self):
"""Test input filtering"""
self.imp_raster = "imp_filtered"
Expand Down Expand Up @@ -152,7 +152,7 @@ def test_filter(self):
)
self.assertRastersEqual(self.imp_raster, self.ref_raster, 0)

@unittest.skipIf(shutil_which("r.in.pdal") is None, "Cannot find r.in.pdal")
@unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal")
def test_base_raster(self):
"""Test Z adjustement by base raster"""
self.imp_raster = "imp_base_adj"
Expand Down
3 changes: 1 addition & 2 deletions vector/v.in.pdal/testsuite/test_v_in_pdal_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from grass.gunittest.case import TestCase
from grass.gunittest.main import test
import unittest
from grass.script import shutil_which


class BasicTest(TestCase):
Expand Down Expand Up @@ -72,7 +71,7 @@ def tearDown(self):
"""
self.runModule("g.remove", flags="f", type="vector", name=self.imported_points)

@unittest.skipIf(shutil_which("v.in.pdal") is None, "Cannot find v.in.pdal")
@unittest.skipIf(shutil.which("v.in.pdal") is None, "Cannot find v.in.pdal")
def test_same_data(self):
"""Test to see if the standard outputs are created"""
self.assertModule(
Expand Down
Loading

0 comments on commit f3bc923

Please sign in to comment.