|
@@ -30,9 +30,9 @@ import re
|
|
|
import atexit
|
|
|
import subprocess
|
|
|
import shutil
|
|
|
-import locale
|
|
|
import codecs
|
|
|
|
|
|
+from utils import KeyValue, parse_key_val, basename, encode
|
|
|
from grass.exceptions import ScriptError
|
|
|
|
|
|
# i18N
|
|
@@ -82,20 +82,6 @@ _popen_args = ["bufsize", "executable", "stdin", "stdout", "stderr",
|
|
|
"universal_newlines", "startupinfo", "creationflags"]
|
|
|
|
|
|
|
|
|
-def decode(string):
|
|
|
- enc = locale.getdefaultlocale()[1]
|
|
|
- if enc:
|
|
|
- return string.decode(enc)
|
|
|
-
|
|
|
- return string
|
|
|
-
|
|
|
-def encode(string):
|
|
|
- enc = locale.getdefaultlocale()[1]
|
|
|
- if enc:
|
|
|
- return string.encode(enc)
|
|
|
-
|
|
|
- return string
|
|
|
-
|
|
|
def _make_val(val):
|
|
|
if isinstance(val, types.StringType) or \
|
|
|
isinstance(val, types.UnicodeType):
|
|
@@ -670,38 +656,6 @@ def parser():
|
|
|
|
|
|
return _parse_opts(lines[1:])
|
|
|
|
|
|
-
|
|
|
-def separator(sep):
|
|
|
- """!Returns separator from G_OPT_F_SEP appropriately converted
|
|
|
- to character.
|
|
|
-
|
|
|
- >>> separator('pipe')
|
|
|
- '|'
|
|
|
- >>> separator('comma')
|
|
|
- ','
|
|
|
-
|
|
|
- If the string does not match any of the spearator keywords,
|
|
|
- it is returned as is:
|
|
|
-
|
|
|
- >>> separator(', ')
|
|
|
- ', '
|
|
|
-
|
|
|
- @param separator character or separator keyword
|
|
|
-
|
|
|
- @return separator character
|
|
|
- """
|
|
|
- if sep == "pipe":
|
|
|
- return "|"
|
|
|
- elif sep == "comma":
|
|
|
- return ","
|
|
|
- elif sep == "space":
|
|
|
- return " "
|
|
|
- elif sep == "tab" or sep == "\\t":
|
|
|
- return "\t"
|
|
|
- elif sep == "newline" or sep == "\\n":
|
|
|
- return "\n"
|
|
|
- return sep
|
|
|
-
|
|
|
# interface to g.tempfile
|
|
|
|
|
|
|
|
@@ -728,81 +682,6 @@ def tempdir():
|
|
|
return tmp
|
|
|
|
|
|
|
|
|
-class KeyValue(dict):
|
|
|
- """A general-purpose key-value store.
|
|
|
-
|
|
|
- KeyValue is a subclass of dict, but also allows entries to be read and
|
|
|
- written using attribute syntax. Example:
|
|
|
-
|
|
|
- \code
|
|
|
- >>> reg = KeyValue()
|
|
|
- >>> reg['north'] = 489
|
|
|
- >>> reg.north
|
|
|
- 489
|
|
|
- >>> reg.south = 205
|
|
|
- >>> reg['south']
|
|
|
- 205
|
|
|
-
|
|
|
- \endcode
|
|
|
- """
|
|
|
-
|
|
|
- def __getattr__(self, key):
|
|
|
- return self[key]
|
|
|
-
|
|
|
- def __setattr__(self, key, value):
|
|
|
- self[key] = value
|
|
|
-
|
|
|
-# key-value parsers
|
|
|
-
|
|
|
-
|
|
|
-def parse_key_val(s, sep='=', dflt=None, val_type=None, vsep=None):
|
|
|
- """!Parse a string into a dictionary, where entries are separated
|
|
|
- by newlines and the key and value are separated by `sep' (default: `=')
|
|
|
-
|
|
|
- >>> parse_key_val('min=20\\nmax=50') == {'min': '20', 'max': '50'}
|
|
|
- True
|
|
|
- >>> parse_key_val('min=20\\nmax=50',
|
|
|
- ... val_type=float) == {'min': 20, 'max': 50}
|
|
|
- True
|
|
|
-
|
|
|
- @param s string to be parsed
|
|
|
- @param sep key/value separator
|
|
|
- @param dflt default value to be used
|
|
|
- @param val_type value type (None for no cast)
|
|
|
- @param vsep vertical separator (default is Python 'universal newlines' approach)
|
|
|
-
|
|
|
- @return parsed input (dictionary of keys/values)
|
|
|
- """
|
|
|
- result = KeyValue()
|
|
|
-
|
|
|
- if not s:
|
|
|
- return result
|
|
|
-
|
|
|
- if vsep:
|
|
|
- lines = s.split(vsep)
|
|
|
- try:
|
|
|
- lines.remove('\n')
|
|
|
- except ValueError:
|
|
|
- pass
|
|
|
- else:
|
|
|
- lines = s.splitlines()
|
|
|
-
|
|
|
- for line in lines:
|
|
|
- kv = line.split(sep, 1)
|
|
|
- k = kv[0].strip()
|
|
|
- if len(kv) > 1:
|
|
|
- v = kv[1].strip()
|
|
|
- else:
|
|
|
- v = dflt
|
|
|
-
|
|
|
- if val_type:
|
|
|
- result[k] = val_type(v)
|
|
|
- else:
|
|
|
- result[k] = v
|
|
|
-
|
|
|
- return result
|
|
|
-
|
|
|
-
|
|
|
def _compare_projection(dic):
|
|
|
"""
|
|
|
!Check if projection has some possibility of duplicate names like
|
|
@@ -977,23 +856,6 @@ def compare_key_value_text_files(filename_a, filename_b, sep=":",
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
-def diff_files(filename_a, filename_b):
|
|
|
- """!Diffs two text files and returns difference.
|
|
|
-
|
|
|
- @param filename_a first file path
|
|
|
- @param filename_b second file path
|
|
|
-
|
|
|
- @return list of strings
|
|
|
- """
|
|
|
- import difflib
|
|
|
- differ = difflib.Differ()
|
|
|
- fh_a = open(filename_a, 'r')
|
|
|
- fh_b = open(filename_b, 'r')
|
|
|
- result = list(differ.compare(fh_a.readlines(),
|
|
|
- fh_b.readlines()))
|
|
|
- return result
|
|
|
-
|
|
|
-
|
|
|
# interface to g.gisenv
|
|
|
|
|
|
|
|
@@ -1456,25 +1318,6 @@ def verbosity():
|
|
|
|
|
|
## various utilities, not specific to GRASS
|
|
|
|
|
|
-# basename inc. extension stripping
|
|
|
-
|
|
|
-
|
|
|
-def basename(path, ext=None):
|
|
|
- """!Remove leading directory components and an optional extension
|
|
|
- from the specified path
|
|
|
-
|
|
|
- @param path path
|
|
|
- @param ext extension
|
|
|
- """
|
|
|
- name = os.path.basename(path)
|
|
|
- if not ext:
|
|
|
- return name
|
|
|
- fs = name.rsplit('.', 1)
|
|
|
- if len(fs) > 1 and fs[1].lower() == ext:
|
|
|
- name = fs[0]
|
|
|
- return name
|
|
|
-
|
|
|
-
|
|
|
def find_program(pgm, *args):
|
|
|
"""!Attempt to run a program, with optional arguments.
|
|
|
|
|
@@ -1511,49 +1354,6 @@ def find_program(pgm, *args):
|
|
|
|
|
|
return found
|
|
|
|
|
|
-# try to remove a file, without complaints
|
|
|
-
|
|
|
-
|
|
|
-def try_remove(path):
|
|
|
- """!Attempt to remove a file; no exception is generated if the
|
|
|
- attempt fails.
|
|
|
-
|
|
|
- @param path path to file to remove
|
|
|
- """
|
|
|
- try:
|
|
|
- os.remove(path)
|
|
|
- except:
|
|
|
- pass
|
|
|
-
|
|
|
-# try to remove a directory, without complaints
|
|
|
-
|
|
|
-
|
|
|
-def try_rmdir(path):
|
|
|
- """!Attempt to remove a directory; no exception is generated if the
|
|
|
- attempt fails.
|
|
|
-
|
|
|
- @param path path to directory to remove
|
|
|
- """
|
|
|
- try:
|
|
|
- os.rmdir(path)
|
|
|
- except:
|
|
|
- shutil.rmtree(path, ignore_errors=True)
|
|
|
-
|
|
|
-
|
|
|
-def float_or_dms(s):
|
|
|
- """!Convert DMS to float.
|
|
|
-
|
|
|
- >>> round(float_or_dms('26:45:30'), 5)
|
|
|
- 26.75833
|
|
|
- >>> round(float_or_dms('26:0:0.1'), 5)
|
|
|
- 26.00003
|
|
|
-
|
|
|
- @param s DMS value
|
|
|
-
|
|
|
- @return float value
|
|
|
- """
|
|
|
- return sum(float(x) / 60 ** n for (n, x) in enumerate(s.split(':')))
|
|
|
-
|
|
|
# interface to g.mapsets
|
|
|
|
|
|
|