浏览代码

pythonlib: add env variables to all relevant functions (#677)

Passing environment is needed for some functions for fixes of r.import.
The rest of the functions get it for consistency.

The following functions have newly added env parameter:
* core.py: tempfile, tempdir, locn_is_latlong, find_file, list_strings, list_pairs, list_grouped, mapsets
* db.py: db_describe, db_table_exist, db_connection, db_select, db_table_in_vector
* raster.py: raster_history, raster_info
* raster3d.py: raster3d_info
* vector.py: vector_db, vector_layer_db, vector_columns, vector_history, vector_info_topo, vector_info, vector_db_select, vector_what
* array.py
Anna Petrasova 4 年之前
父节点
当前提交
dbeb5f36cb
共有 6 个文件被更改,包括 129 次插入78 次删除
  1. 20 12
      lib/python/script/array.py
  2. 40 17
      lib/python/script/core.py
  3. 20 14
      lib/python/script/db.py
  4. 10 8
      lib/python/script/raster.py
  5. 3 2
      lib/python/script/raster3d.py
  6. 36 25
      lib/python/script/vector.py

+ 20 - 12
lib/python/script/array.py

@@ -124,8 +124,8 @@ from grass.exceptions import CalledModuleError
 ###############################################################################
 ###############################################################################
 
 
 class _tempfile(object):
 class _tempfile(object):
-    def __init__(self):
-        self.filename = gcore.tempfile()
+    def __init__(self, env=None):
+        self.filename = gcore.tempfile(env=env)
 
 
     def __del__(self):
     def __del__(self):
         try_remove(self.filename)
         try_remove(self.filename)
@@ -133,18 +133,19 @@ class _tempfile(object):
 ###############################################################################
 ###############################################################################
 
 
 class array(numpy.memmap):
 class array(numpy.memmap):
-    def __new__(cls, mapname=None, null=None, dtype=numpy.double):
+    def __new__(cls, mapname=None, null=None, dtype=numpy.double, env=None):
         """Define new numpy array
         """Define new numpy array
 
 
         :param cls:
         :param cls:
         :param dtype: data type (default: numpy.double)
         :param dtype: data type (default: numpy.double)
+        :param env: environment
         """
         """
-        reg = gcore.region()
+        reg = gcore.region(env=env)
         r = reg['rows']
         r = reg['rows']
         c = reg['cols']
         c = reg['cols']
         shape = (r, c)
         shape = (r, c)
 
 
-        tempfile = _tempfile()
+        tempfile = _tempfile(env)
         if mapname:
         if mapname:
             kind = numpy.dtype(dtype).kind
             kind = numpy.dtype(dtype).kind
             size = numpy.dtype(dtype).itemsize
             size = numpy.dtype(dtype).itemsize
@@ -167,7 +168,8 @@ class array(numpy.memmap):
                 bytes=size,
                 bytes=size,
                 null=null,
                 null=null,
                 quiet=True,
                 quiet=True,
-                overwrite=True)
+                overwrite=True,
+                env=env)
 
 
         self = numpy.memmap.__new__(
         self = numpy.memmap.__new__(
             cls,
             cls,
@@ -178,6 +180,7 @@ class array(numpy.memmap):
 
 
         self.tempfile = tempfile
         self.tempfile = tempfile
         self.filename = tempfile.filename
         self.filename = tempfile.filename
+        self._env = env
         return self
         return self
 
 
     def read(self, mapname, null=None):
     def read(self, mapname, null=None):
@@ -253,7 +256,7 @@ class array(numpy.memmap):
         else:
         else:
             raise ValueError(_('Invalid kind <%s>') % kind)
             raise ValueError(_('Invalid kind <%s>') % kind)
 
 
-        reg = gcore.region()
+        reg = gcore.region(env=self._env)
 
 
         try:
         try:
             gcore.run_command(
             gcore.run_command(
@@ -271,7 +274,8 @@ class array(numpy.memmap):
                 east=reg['e'],
                 east=reg['e'],
                 west=reg['w'],
                 west=reg['w'],
                 rows=reg['rows'],
                 rows=reg['rows'],
-                cols=reg['cols'])
+                cols=reg['cols'],
+                env=self._env)
         except CalledModuleError:
         except CalledModuleError:
             return 1
             return 1
         else:
         else:
@@ -281,11 +285,12 @@ class array(numpy.memmap):
 
 
 
 
 class array3d(numpy.memmap):
 class array3d(numpy.memmap):
-    def __new__(cls, mapname=None, null=None, dtype=numpy.double):
+    def __new__(cls, mapname=None, null=None, dtype=numpy.double, env=None):
         """Define new 3d numpy array
         """Define new 3d numpy array
 
 
         :param cls:
         :param cls:
         :param dtype: data type (default: numpy.double)
         :param dtype: data type (default: numpy.double)
+        :param env: environment
         """
         """
         reg = gcore.region(True)
         reg = gcore.region(True)
         r = reg['rows3']
         r = reg['rows3']
@@ -316,7 +321,8 @@ class array3d(numpy.memmap):
                 bytes=size,
                 bytes=size,
                 null=null,
                 null=null,
                 quiet=True,
                 quiet=True,
-                overwrite=True)
+                overwrite=True,
+                env=env)
 
 
         self = numpy.memmap.__new__(
         self = numpy.memmap.__new__(
             cls,
             cls,
@@ -327,6 +333,7 @@ class array3d(numpy.memmap):
 
 
         self.tempfile = tempfile
         self.tempfile = tempfile
         self.filename = tempfile.filename
         self.filename = tempfile.filename
+        self._env = env
 
 
         return self
         return self
 
 
@@ -398,7 +405,7 @@ class array3d(numpy.memmap):
         else:
         else:
             raise ValueError(_('Invalid kind <%s>') % kind)
             raise ValueError(_('Invalid kind <%s>') % kind)
 
 
-        reg = gcore.region(True)
+        reg = gcore.region(True, env=self._env)
 
 
         try:
         try:
             gcore.run_command(
             gcore.run_command(
@@ -418,7 +425,8 @@ class array3d(numpy.memmap):
                 west=reg['w'],
                 west=reg['w'],
                 depths=reg['depths'],
                 depths=reg['depths'],
                 rows=reg['rows3'],
                 rows=reg['rows3'],
-                cols=reg['cols3'])
+                cols=reg['cols3'],
+                env=self._env)
 
 
         except CalledModuleError:
         except CalledModuleError:
             return 1
             return 1

+ 40 - 17
lib/python/script/core.py

@@ -904,10 +904,11 @@ def parser():
 # interface to g.tempfile
 # interface to g.tempfile
 
 
 
 
-def tempfile(create=True):
+def tempfile(create=True, env=None):
     """Returns the name of a temporary file, created with g.tempfile.
     """Returns the name of a temporary file, created with g.tempfile.
 
 
     :param bool create: True to create a file
     :param bool create: True to create a file
+    :param env: environment
 
 
     :return: path to a tmp file
     :return: path to a tmp file
     """
     """
@@ -915,12 +916,12 @@ def tempfile(create=True):
     if not create:
     if not create:
         flags += 'd'
         flags += 'd'
 
 
-    return read_command("g.tempfile", flags=flags, pid=os.getpid()).strip()
+    return read_command("g.tempfile", flags=flags, pid=os.getpid(), env=env).strip()
 
 
 
 
-def tempdir():
+def tempdir(env=None):
     """Returns the name of a temporary dir, created with g.tempfile."""
     """Returns the name of a temporary dir, created with g.tempfile."""
-    tmp = tempfile(create=False)
+    tmp = tempfile(create=False, env=env)
     os.mkdir(tmp)
     os.mkdir(tmp)
 
 
     return tmp
     return tmp
@@ -1144,13 +1145,13 @@ def gisenv(env=None):
 # interface to g.region
 # interface to g.region
 
 
 
 
-def locn_is_latlong():
+def locn_is_latlong(env=None):
     """Tests if location is lat/long. Value is obtained
     """Tests if location is lat/long. Value is obtained
     by checking the "g.region -pu" projection code.
     by checking the "g.region -pu" projection code.
 
 
     :return: True for a lat/long region, False otherwise
     :return: True for a lat/long region, False otherwise
     """
     """
-    s = read_command("g.region", flags='pu')
+    s = read_command("g.region", flags='pu', env=env)
     kv = parse_key_val(s, ':')
     kv = parse_key_val(s, ':')
     if kv['projection'].split(' ')[0] == '3':
     if kv['projection'].split(' ')[0] == '3':
         return True
         return True
@@ -1295,7 +1296,7 @@ def del_temp_region():
 # interface to g.findfile
 # interface to g.findfile
 
 
 
 
-def find_file(name, element='cell', mapset=None):
+def find_file(name, element='cell', mapset=None, env=None):
     """Returns the output from running g.findfile as a
     """Returns the output from running g.findfile as a
     dictionary. Example:
     dictionary. Example:
 
 
@@ -1309,6 +1310,7 @@ def find_file(name, element='cell', mapset=None):
     :param str name: file name
     :param str name: file name
     :param str element: element type (default 'cell')
     :param str element: element type (default 'cell')
     :param str mapset: mapset name (default all mapsets in search path)
     :param str mapset: mapset name (default all mapsets in search path)
+    :param env: environment
 
 
     :return: parsed output of g.findfile
     :return: parsed output of g.findfile
     """
     """
@@ -1319,14 +1321,15 @@ def find_file(name, element='cell', mapset=None):
     # se we ignore return code and just focus on stdout
     # se we ignore return code and just focus on stdout
     process = start_command('g.findfile', flags='n',
     process = start_command('g.findfile', flags='n',
                             element=element, file=name, mapset=mapset,
                             element=element, file=name, mapset=mapset,
-                            stdout=PIPE)
+                            stdout=PIPE, env=env)
     stdout = process.communicate()[0]
     stdout = process.communicate()[0]
     return parse_key_val(stdout)
     return parse_key_val(stdout)
 
 
 # interface to g.list
 # interface to g.list
 
 
 
 
-def list_strings(type, pattern=None, mapset=None, exclude=None, flag=''):
+def list_strings(type, pattern=None, mapset=None, exclude=None,
+                 flag='', env=None):
     """List of elements as strings.
     """List of elements as strings.
 
 
     Returns the output from running g.list, as a list of qualified
     Returns the output from running g.list, as a list of qualified
@@ -1338,6 +1341,7 @@ def list_strings(type, pattern=None, mapset=None, exclude=None, flag=''):
     :param str exclude: pattern string to exclude maps from the research
     :param str exclude: pattern string to exclude maps from the research
     :param str flag: pattern type: 'r' (basic regexp), 'e' (extended regexp),
     :param str flag: pattern type: 'r' (basic regexp), 'e' (extended regexp),
                      or '' (glob pattern)
                      or '' (glob pattern)
+    :param env: environment
 
 
     :return: list of elements
     :return: list of elements
     """
     """
@@ -1351,13 +1355,15 @@ def list_strings(type, pattern=None, mapset=None, exclude=None, flag=''):
                              type=type,
                              type=type,
                              pattern=pattern,
                              pattern=pattern,
                              exclude=exclude,
                              exclude=exclude,
-                             mapset=mapset).splitlines():
+                             mapset=mapset,
+                             env=env).splitlines():
         result.append(line.strip())
         result.append(line.strip())
 
 
     return result
     return result
 
 
 
 
-def list_pairs(type, pattern=None, mapset=None, exclude=None, flag=''):
+def list_pairs(type, pattern=None, mapset=None, exclude=None,
+               flag='', env=None):
     """List of elements as pairs
     """List of elements as pairs
 
 
     Returns the output from running g.list, as a list of
     Returns the output from running g.list, as a list of
@@ -1369,16 +1375,17 @@ def list_pairs(type, pattern=None, mapset=None, exclude=None, flag=''):
     :param str exclude: pattern string to exclude maps from the research
     :param str exclude: pattern string to exclude maps from the research
     :param str flag: pattern type: 'r' (basic regexp), 'e' (extended regexp),
     :param str flag: pattern type: 'r' (basic regexp), 'e' (extended regexp),
                      or '' (glob pattern)
                      or '' (glob pattern)
+    :param env: environment
 
 
     :return: list of elements
     :return: list of elements
     """
     """
     return [tuple(map.split('@', 1)) for map in list_strings(type, pattern,
     return [tuple(map.split('@', 1)) for map in list_strings(type, pattern,
                                                               mapset, exclude,
                                                               mapset, exclude,
-                                                              flag)]
+                                                              flag, env)]
 
 
 
 
 def list_grouped(type, pattern=None, check_search_path=True, exclude=None,
 def list_grouped(type, pattern=None, check_search_path=True, exclude=None,
-                 flag=''):
+                 flag='', env=None):
     """List of elements grouped by mapsets.
     """List of elements grouped by mapsets.
 
 
     Returns the output from running g.list, as a dictionary where the
     Returns the output from running g.list, as a dictionary where the
@@ -1395,6 +1402,7 @@ def list_grouped(type, pattern=None, check_search_path=True, exclude=None,
     :param str exclude: pattern string to exclude maps from the research
     :param str exclude: pattern string to exclude maps from the research
     :param str flag: pattern type: 'r' (basic regexp), 'e' (extended regexp),
     :param str flag: pattern type: 'r' (basic regexp), 'e' (extended regexp),
                                     or '' (glob pattern)
                                     or '' (glob pattern)
+    :param env: environment
 
 
     :return: directory of mapsets/elements
     :return: directory of mapsets/elements
     """
     """
@@ -1411,7 +1419,7 @@ def list_grouped(type, pattern=None, check_search_path=True, exclude=None,
             types[i] = 'raster'
             types[i] = 'raster'
     result = {}
     result = {}
     if check_search_path:
     if check_search_path:
-        for mapset in mapsets(search_path=True):
+        for mapset in mapsets(search_path=True, env=env):
             if store_types:
             if store_types:
                 result[mapset] = {}
                 result[mapset] = {}
             else:
             else:
@@ -1419,7 +1427,8 @@ def list_grouped(type, pattern=None, check_search_path=True, exclude=None,
 
 
     mapset = None
     mapset = None
     for line in read_command("g.list", quiet=True, flags="m" + flag,
     for line in read_command("g.list", quiet=True, flags="m" + flag,
-                             type=types, pattern=pattern, exclude=exclude).splitlines():
+                             type=types, pattern=pattern,
+                             exclude=exclude, env=env).splitlines():
         try:
         try:
             name, mapset = line.split('@')
             name, mapset = line.split('@')
         except ValueError:
         except ValueError:
@@ -1546,7 +1555,7 @@ def find_program(pgm, *args):
 # interface to g.mapsets
 # interface to g.mapsets
 
 
 
 
-def mapsets(search_path=False):
+def mapsets(search_path=False, env=None):
     """List available mapsets
     """List available mapsets
 
 
     :param bool search_path: True to list mapsets only in search path
     :param bool search_path: True to list mapsets only in search path
@@ -1560,7 +1569,8 @@ def mapsets(search_path=False):
     mapsets = read_command('g.mapsets',
     mapsets = read_command('g.mapsets',
                            flags=flags,
                            flags=flags,
                            sep='newline',
                            sep='newline',
-                           quiet=True)
+                           quiet=True,
+                           env=env)
     if not mapsets:
     if not mapsets:
         fatal(_("Unable to list mapsets"))
         fatal(_("Unable to list mapsets"))
 
 
@@ -1767,6 +1777,17 @@ def legal_name(s):
     return True
     return True
 
 
 
 
+def sanitize_mapset_environment(env):
+    """Remove environmental variables relevant only
+    for a specific mapset. This should be called
+    when a copy of environment is used with a different mapset."""
+    if "WIND_OVERRIDE" in env:
+        del env["WIND_OVERRIDE"]
+    if "GRASS_REGION" in env:
+        del env["GRASS_REGION"]
+    return env
+
+
 def create_environment(gisdbase, location, mapset):
 def create_environment(gisdbase, location, mapset):
     """Creates environment to be passed in run_command for example.
     """Creates environment to be passed in run_command for example.
     Returns tuple with temporary file path and the environment. The user
     Returns tuple with temporary file path and the environment. The user
@@ -1778,6 +1799,8 @@ def create_environment(gisdbase, location, mapset):
         f.write('GUI: text\n')
         f.write('GUI: text\n')
     env = os.environ.copy()
     env = os.environ.copy()
     env['GISRC'] = f.name
     env['GISRC'] = f.name
+    # remove mapset-specific env vars
+    env = sanitize_mapset_environment(env)
     return f.name, env
     return f.name, env
 
 
 
 

+ 20 - 14
lib/python/script/db.py

@@ -24,7 +24,7 @@ from .utils import try_remove
 from grass.exceptions import CalledModuleError
 from grass.exceptions import CalledModuleError
 
 
 
 
-def db_describe(table, **args):
+def db_describe(table, env=None, **args):
     """Return the list of columns for a database table
     """Return the list of columns for a database table
     (interface to `db.describe -c`). Example:
     (interface to `db.describe -c`). Example:
 
 
@@ -37,6 +37,7 @@ def db_describe(table, **args):
 
 
     :param str table: table name
     :param str table: table name
     :param list args:
     :param list args:
+    :param env: environment
 
 
     :return: parsed module output
     :return: parsed module output
     """
     """
@@ -44,7 +45,7 @@ def db_describe(table, **args):
         args.pop('database')
         args.pop('database')
     if 'driver' in args and args['driver'] == '':
     if 'driver' in args and args['driver'] == '':
         args.pop('driver')
         args.pop('driver')
-    s = read_command('db.describe', flags='c', table=table, **args)
+    s = read_command('db.describe', flags='c', table=table, env=env, **args)
     if not s:
     if not s:
         fatal(_("Unable to describe table <%s>") % table)
         fatal(_("Unable to describe table <%s>") % table)
 
 
@@ -66,7 +67,7 @@ def db_describe(table, **args):
     return result
     return result
 
 
 
 
-def db_table_exist(table, **args):
+def db_table_exist(table, env=None, **args):
     """Check if table exists.
     """Check if table exists.
 
 
     If no driver or database are given, then default settings is used
     If no driver or database are given, then default settings is used
@@ -81,6 +82,7 @@ def db_table_exist(table, **args):
 
 
     :param str table: table name
     :param str table: table name
     :param args:
     :param args:
+    :param env: environment
 
 
     :return: True for success, False otherwise
     :return: True for success, False otherwise
     """
     """
@@ -88,7 +90,7 @@ def db_table_exist(table, **args):
     ok = True
     ok = True
     try:
     try:
         run_command('db.describe', flags='c', table=table,
         run_command('db.describe', flags='c', table=table,
-                    stdout=nuldev, stderr=nuldev, **args)
+                    stdout=nuldev, stderr=nuldev, env=env, **args)
     except CalledModuleError:
     except CalledModuleError:
         ok = False
         ok = False
     finally:
     finally:
@@ -97,7 +99,7 @@ def db_table_exist(table, **args):
     return ok
     return ok
 
 
 
 
-def db_connection(force=False):
+def db_connection(force=False, env=None):
     """Return the current database connection parameters
     """Return the current database connection parameters
     (interface to `db.connect -g`). Example:
     (interface to `db.connect -g`). Example:
 
 
@@ -105,23 +107,25 @@ def db_connection(force=False):
     {'group': '', 'schema': '', 'driver': 'sqlite', 'database': '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db'}
     {'group': '', 'schema': '', 'driver': 'sqlite', 'database': '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db'}
 
 
     :param force True to set up default DB connection if not defined
     :param force True to set up default DB connection if not defined
+    :param env: environment
 
 
     :return: parsed output of db.connect
     :return: parsed output of db.connect
     """
     """
     try:
     try:
         nuldev = open(os.devnull, 'w')
         nuldev = open(os.devnull, 'w')
-        conn = parse_command('db.connect', flags='g', stderr=nuldev)
+        conn = parse_command('db.connect', flags='g', stderr=nuldev, env=env)
         nuldev.close()
         nuldev.close()
     except CalledModuleError:
     except CalledModuleError:
         conn = None
         conn = None
     
     
     if not conn and force:
     if not conn and force:
-        run_command('db.connect', flags='c')
-        conn = parse_command('db.connect', flags='g')
+        run_command('db.connect', flags='c', env=env)
+        conn = parse_command('db.connect', flags='g', env=env)
 
 
     return conn
     return conn
 
 
-def db_select(sql=None, filename=None, table=None, **args):
+
+def db_select(sql=None, filename=None, table=None, env=None, **args):
     """Perform SQL select statement
     """Perform SQL select statement
 
 
     Note: one of <em>sql</em>, <em>filename</em>, or <em>table</em>
     Note: one of <em>sql</em>, <em>filename</em>, or <em>table</em>
@@ -145,8 +149,9 @@ def db_select(sql=None, filename=None, table=None, **args):
     :param str filename: name of file with SQL statements (or None)
     :param str filename: name of file with SQL statements (or None)
     :param str table: name of table to query (or None)
     :param str table: name of table to query (or None)
     :param str args:  see \gmod{db.select} arguments
     :param str args:  see \gmod{db.select} arguments
+    :param env: environment
     """
     """
-    fname = tempfile(create=False)
+    fname = tempfile(create=False, env=env)
     if sql:
     if sql:
         args['sql'] = sql
         args['sql'] = sql
     elif filename:
     elif filename:
@@ -162,7 +167,7 @@ def db_select(sql=None, filename=None, table=None, **args):
 
 
     try:
     try:
         run_command('db.select', quiet=True, flags='c',
         run_command('db.select', quiet=True, flags='c',
-                    output=fname, **args)
+                    output=fname, env=env, **args)
     except CalledModuleError:
     except CalledModuleError:
         fatal(_("Fetching data failed"))
         fatal(_("Fetching data failed"))
 
 
@@ -174,7 +179,7 @@ def db_select(sql=None, filename=None, table=None, **args):
     return tuple(result)
     return tuple(result)
 
 
 
 
-def db_table_in_vector(table, mapset='.'):
+def db_table_in_vector(table, mapset='.', env=None):
     """Return the name of vector connected to the table.
     """Return the name of vector connected to the table.
     By default it check only in the current mapset, because the same table
     By default it check only in the current mapset, because the same table
     name could be used also in other mapset by other vector.
     name could be used also in other mapset by other vector.
@@ -189,13 +194,14 @@ def db_table_in_vector(table, mapset='.'):
     0
     0
 
 
     :param str table: name of table to query
     :param str table: name of table to query
+    :param env: environment
     """
     """
     from .vector import vector_db
     from .vector import vector_db
     nuldev = open(os.devnull, 'w')
     nuldev = open(os.devnull, 'w')
     used = []
     used = []
-    vects = list_strings('vector', mapset=mapset)
+    vects = list_strings('vector', mapset=mapset, env=env)
     for vect in vects:
     for vect in vects:
-        for f in vector_db(vect, stderr=nuldev).values():
+        for f in vector_db(vect, stderr=nuldev, env=env).values():
             if not f:
             if not f:
                 continue
                 continue
             if f['table'] == table:
             if f['table'] == table:

+ 10 - 8
lib/python/script/raster.py

@@ -33,27 +33,28 @@ if sys.version_info.major >= 3:
     unicode = str
     unicode = str
 
 
 
 
-def raster_history(map, overwrite=False):
+def raster_history(map, overwrite=False, env=None):
     """Set the command history for a raster map to the command used to
     """Set the command history for a raster map to the command used to
     invoke the script (interface to `r.support`).
     invoke the script (interface to `r.support`).
 
 
     :param str map: map name
     :param str map: map name
+    :param env: environment
 
 
     :return: True on success
     :return: True on success
     :return: False on failure
     :return: False on failure
 
 
     """
     """
-    current_mapset = gisenv()['MAPSET']
-    if find_file(name=map)['mapset'] == current_mapset:
+    current_mapset = gisenv(env)['MAPSET']
+    if find_file(name=map, env=env)['mapset'] == current_mapset:
         if overwrite == True:
         if overwrite == True:
-            historyfile = tempfile()
+            historyfile = tempfile(env=env)
             f = open(historyfile, 'w')
             f = open(historyfile, 'w')
             f.write(os.environ['CMDLINE'])
             f.write(os.environ['CMDLINE'])
             f.close()
             f.close()
-            run_command('r.support', map=map, loadhistory=historyfile)
+            run_command('r.support', map=map, loadhistory=historyfile, env=env)
             try_remove(historyfile)
             try_remove(historyfile)
         else:
         else:
-            run_command('r.support', map=map, history=os.environ['CMDLINE'])
+            run_command('r.support', map=map, history=os.environ['CMDLINE'], env=env)
         return True
         return True
 
 
     warning(_("Unable to write history for <%(map)s>. "
     warning(_("Unable to write history for <%(map)s>. "
@@ -61,7 +62,7 @@ def raster_history(map, overwrite=False):
     return False
     return False
 
 
 
 
-def raster_info(map):
+def raster_info(map, env=None):
     """Return information about a raster map (interface to
     """Return information about a raster map (interface to
     `r.info -gre`). Example:
     `r.info -gre`). Example:
 
 
@@ -69,6 +70,7 @@ def raster_info(map):
     {'creator': '"helena"', 'cols': '1500' ... 'south': 215000.0}
     {'creator': '"helena"', 'cols': '1500' ... 'south': 215000.0}
 
 
     :param str map: map name
     :param str map: map name
+    :param env: environment
 
 
     :return: parsed raster info
     :return: parsed raster info
 
 
@@ -80,7 +82,7 @@ def raster_info(map):
         else:
         else:
             return float(s)
             return float(s)
 
 
-    s = read_command('r.info', flags='gre', map=map)
+    s = read_command('r.info', flags='gre', map=map, env=env)
     kv = parse_key_val(s)
     kv = parse_key_val(s)
     for k in ['min', 'max']:
     for k in ['min', 'max']:
         kv[k] = float_or_null(kv[k])
         kv[k] = float_or_null(kv[k])

+ 3 - 2
lib/python/script/raster3d.py

@@ -27,7 +27,7 @@ from .utils import float_or_dms, parse_key_val
 from grass.exceptions import CalledModuleError
 from grass.exceptions import CalledModuleError
 
 
 
 
-def raster3d_info(map):
+def raster3d_info(map, env=None):
     """Return information about a raster3d map (interface to `r3.info`).
     """Return information about a raster3d map (interface to `r3.info`).
     Example:
     Example:
 
 
@@ -38,6 +38,7 @@ def raster3d_info(map):
     0
     0
 
 
     :param str map: map name
     :param str map: map name
+    :param env: environment
 
 
     :return: parsed raster3d info
     :return: parsed raster3d info
     """
     """
@@ -48,7 +49,7 @@ def raster3d_info(map):
         else:
         else:
             return float(s)
             return float(s)
 
 
-    s = read_command('r3.info', flags='rg', map=map)
+    s = read_command('r3.info', flags='rg', map=map, env=env)
     kv = parse_key_val(s)
     kv = parse_key_val(s)
     for k in ['min', 'max']:
     for k in ['min', 'max']:
         kv[k] = float_or_null(kv[k])
         kv[k] = float_or_null(kv[k])

+ 36 - 25
lib/python/script/vector.py

@@ -33,7 +33,7 @@ from .core import *
 from grass.exceptions import CalledModuleError
 from grass.exceptions import CalledModuleError
 
 
 
 
-def vector_db(map, **args):
+def vector_db(map, env=None, **kwargs):
     """Return the database connection details for a vector map
     """Return the database connection details for a vector map
     (interface to `v.db.connect -g`). Example:
     (interface to `v.db.connect -g`). Example:
 
 
@@ -41,12 +41,13 @@ def vector_db(map, **args):
     {1: {'layer': 1, ... 'table': 'geology'}}
     {1: {'layer': 1, ... 'table': 'geology'}}
 
 
     :param str map: vector map
     :param str map: vector map
-    :param args: other v.db.connect's arguments
+    :param kwargs: other v.db.connect's arguments
+    :param env: environment
 
 
     :return: dictionary
     :return: dictionary
     """
     """
     s = read_command('v.db.connect', quiet=True, flags='g', map=map, sep=';',
     s = read_command('v.db.connect', quiet=True, flags='g', map=map, sep=';',
-                     **args)
+                     env=env, **kwargs)
     result = {}
     result = {}
 
 
     for l in s.splitlines():
     for l in s.splitlines():
@@ -73,17 +74,18 @@ def vector_db(map, **args):
     return result
     return result
 
 
 
 
-def vector_layer_db(map, layer):
+def vector_layer_db(map, layer, env=None):
     """Return the database connection details for a vector map layer.
     """Return the database connection details for a vector map layer.
     If db connection for given layer is not defined, fatal() is called.
     If db connection for given layer is not defined, fatal() is called.
 
 
     :param str map: map name
     :param str map: map name
     :param layer: layer number
     :param layer: layer number
+    :param env: environment
 
 
     :return: parsed output
     :return: parsed output
     """
     """
     try:
     try:
-        f = vector_db(map)[int(layer)]
+        f = vector_db(map, env=env)[int(layer)]
     except KeyError:
     except KeyError:
         fatal(_("Database connection not defined for layer %s") % layer)
         fatal(_("Database connection not defined for layer %s") % layer)
 
 
@@ -92,7 +94,7 @@ def vector_layer_db(map, layer):
 # run "v.info -c ..." and parse output
 # run "v.info -c ..." and parse output
 
 
 
 
-def vector_columns(map, layer=None, getDict=True, **args):
+def vector_columns(map, layer=None, getDict=True, env=None, **kwargs):
     """Return a dictionary (or a list) of the columns for the
     """Return a dictionary (or a list) of the columns for the
     database table connected to a vector map (interface to `v.info -c`).
     database table connected to a vector map (interface to `v.info -c`).
 
 
@@ -118,12 +120,13 @@ def vector_columns(map, layer=None, getDict=True, **args):
     :param layer: layer number or name (None for all layers)
     :param layer: layer number or name (None for all layers)
     :param bool getDict: True to return dictionary of columns otherwise list
     :param bool getDict: True to return dictionary of columns otherwise list
                          of column names is returned
                          of column names is returned
-    :param args: (v.info's arguments)
+    :param kwargs: (v.info's arguments)
+    :param env: environment
 
 
     :return: dictionary/list of columns
     :return: dictionary/list of columns
     """
     """
     s = read_command('v.info', flags='c', map=map, layer=layer, quiet=True,
     s = read_command('v.info', flags='c', map=map, layer=layer, quiet=True,
-                     **args)
+                     env=env, **kwargs)
     if getDict:
     if getDict:
         result = dict()
         result = dict()
     else:
     else:
@@ -140,20 +143,21 @@ def vector_columns(map, layer=None, getDict=True, **args):
     return result
     return result
 
 
 
 
-def vector_history(map, replace=False):
+def vector_history(map, replace=False, env=None):
     """Set the command history for a vector map to the command used to
     """Set the command history for a vector map to the command used to
     invoke the script (interface to `v.support`).
     invoke the script (interface to `v.support`).
 
 
     :param str map: mapname
     :param str map: mapname
     :param bool replace: Replace command line instead of appending it
     :param bool replace: Replace command line instead of appending it
+    :param env: environment
 
 
     :return: v.support output
     :return: v.support output
     """
     """
     run_command('v.support', map=map, cmdhist=os.environ['CMDLINE'],
     run_command('v.support', map=map, cmdhist=os.environ['CMDLINE'],
-                flags='h' if replace else None)
+                flags='h' if replace else None, env=env)
 
 
 
 
-def vector_info_topo(map, layer=1):
+def vector_info_topo(map, layer=1, env=None):
     """Return information about a vector map (interface to `v.info -t`).
     """Return information about a vector map (interface to `v.info -t`).
     Example:
     Example:
 
 
@@ -164,10 +168,12 @@ def vector_info_topo(map, layer=1):
 
 
     :param str map: map name
     :param str map: map name
     :param int layer: layer number
     :param int layer: layer number
+    :param env: environment
 
 
     :return: parsed output
     :return: parsed output
     """
     """
-    s = read_command('v.info', flags='t', layer=layer, map=map)
+    s = read_command('v.info', flags='t', layer=layer, map=map,
+                     env=env)
     ret = parse_key_val(s, val_type=int)
     ret = parse_key_val(s, val_type=int)
     if 'map3d' in ret:
     if 'map3d' in ret:
         ret['map3d'] = bool(ret['map3d'])
         ret['map3d'] = bool(ret['map3d'])
@@ -175,7 +181,7 @@ def vector_info_topo(map, layer=1):
     return ret
     return ret
 
 
 
 
-def vector_info(map, layer=1):
+def vector_info(map, layer=1, env=None):
     """Return information about a vector map (interface to
     """Return information about a vector map (interface to
     `v.info`). Example:
     `v.info`). Example:
 
 
@@ -184,11 +190,13 @@ def vector_info(map, layer=1):
 
 
     :param str map: map name
     :param str map: map name
     :param int layer: layer number
     :param int layer: layer number
+    :param env: environment
 
 
     :return: parsed vector info
     :return: parsed vector info
     """
     """
 
 
-    s = read_command('v.info', flags='get', layer=layer, map=map)
+    s = read_command('v.info', flags='get', layer=layer, map=map,
+                     env=env)
 
 
     kv = parse_key_val(s)
     kv = parse_key_val(s)
     for k in ['north', 'south', 'east', 'west', 'top', 'bottom']:
     for k in ['north', 'south', 'east', 'west', 'top', 'bottom']:
@@ -207,7 +215,7 @@ def vector_info(map, layer=1):
     return kv
     return kv
 
 
 
 
-def vector_db_select(map, layer=1, **kwargs):
+def vector_db_select(map, layer=1, env=None, **kwargs):
     """Get attribute data of selected vector map layer.
     """Get attribute data of selected vector map layer.
 
 
     Function returns list of columns and dictionary of values ordered by
     Function returns list of columns and dictionary of values ordered by
@@ -223,11 +231,12 @@ def vector_db_select(map, layer=1, **kwargs):
     :param str map: map name
     :param str map: map name
     :param int layer: layer number
     :param int layer: layer number
     :param kwargs: v.db.select options
     :param kwargs: v.db.select options
+    :param env: environment
 
 
     :return: dictionary ('columns' and 'values')
     :return: dictionary ('columns' and 'values')
     """
     """
     try:
     try:
-        key = vector_db(map=map)[layer]['key']
+        key = vector_db(map=map, env=env)[layer]['key']
     except KeyError:
     except KeyError:
         error(_('Missing layer %(layer)d in vector map <%(map)s>') % \
         error(_('Missing layer %(layer)d in vector map <%(map)s>') % \
               {'layer': layer, 'map': map})
               {'layer': layer, 'map': map})
@@ -241,7 +250,8 @@ def vector_db_select(map, layer=1, **kwargs):
             debug("Adding key column to the output")
             debug("Adding key column to the output")
             kwargs['columns'] += ',' + key
             kwargs['columns'] += ',' + key
 
 
-    ret = read_command('v.db.select', map=map, layer=layer, **kwargs)
+    ret = read_command('v.db.select', map=map, layer=layer,
+                       env=env, **kwargs)
 
 
     if not ret:
     if not ret:
         error(_('vector_db_select() failed'))
         error(_('vector_db_select() failed'))
@@ -273,7 +283,9 @@ json = None
 orderedDict = None
 orderedDict = None
 
 
 
 
-def vector_what(map, coord, distance=0.0, ttype=None, encoding=None, skip_attributes=False, layer=None, multiple=False):
+def vector_what(map, coord, distance=0.0, ttype=None,
+                encoding=None, skip_attributes=False,
+                layer=None, multiple=False, env=None):
     """Query vector map at given locations
     """Query vector map at given locations
 
 
     To query one vector map at one location
     To query one vector map at one location
@@ -334,12 +346,14 @@ def vector_what(map, coord, distance=0.0, ttype=None, encoding=None, skip_attrib
     :param layer: layer number or list of layers (one for each vector),
     :param layer: layer number or list of layers (one for each vector),
                   if None, all layers (-1) are used
                   if None, all layers (-1) are used
     :param multiple: find multiple features within threshold distance
     :param multiple: find multiple features within threshold distance
+    :param env: environment
 
 
     :return: parsed list
     :return: parsed list
     """
     """
-    if "LC_ALL" in os.environ:
-        locale = os.environ["LC_ALL"]
-        os.environ["LC_ALL"] = "C"
+    if not env:
+        env = os.environ.copy()
+    if "LC_ALL" in env:
+        env["LC_ALL"] = "C"
 
 
     if isinstance(map, (bytes, unicode)):
     if isinstance(map, (bytes, unicode)):
         map_list = [map]
         map_list = [map]
@@ -380,14 +394,11 @@ def vector_what(map, coord, distance=0.0, ttype=None, encoding=None, skip_attrib
         cmdParams['type'] = ','.join(ttype)
         cmdParams['type'] = ','.join(ttype)
 
 
     try:
     try:
-        ret = read_command('v.what',
+        ret = read_command('v.what', env=env,
                            **cmdParams).strip()
                            **cmdParams).strip()
     except CalledModuleError as e:
     except CalledModuleError as e:
         raise ScriptError(e.msg)
         raise ScriptError(e.msg)
 
 
-    if "LC_ALL" in os.environ:
-        os.environ["LC_ALL"] = locale
-
     data = list()
     data = list()
     if not ret:
     if not ret:
         return data
         return data