utils.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. """
  2. Useful functions to be used in Python scripts.
  3. Usage:
  4. ::
  5. from grass.script import utils as gutils
  6. (C) 2014 by the GRASS Development Team
  7. This program is free software under the GNU General Public
  8. License (>=v2). Read the file COPYING that comes with GRASS
  9. for details.
  10. .. sectionauthor:: Glynn Clements
  11. .. sectionauthor:: Martin Landa <landa.martin gmail.com>
  12. .. sectionauthor:: Anna Petrasova <kratochanna gmail.com>
  13. """
  14. import os
  15. import sys
  16. import shutil
  17. import locale
  18. import shlex
  19. def float_or_dms(s):
  20. """Convert DMS to float.
  21. >>> round(float_or_dms('26:45:30'), 5)
  22. 26.75833
  23. >>> round(float_or_dms('26:0:0.1'), 5)
  24. 26.00003
  25. :param s: DMS value
  26. :return: float value
  27. """
  28. return sum(float(x) / 60 ** n for (n, x) in enumerate(s.split(':')))
  29. def separator(sep):
  30. """Returns separator from G_OPT_F_SEP appropriately converted
  31. to character.
  32. >>> separator('pipe')
  33. '|'
  34. >>> separator('comma')
  35. ','
  36. If the string does not match any of the spearator keywords,
  37. it is returned as is:
  38. >>> separator(', ')
  39. ', '
  40. :param str separator: character or separator keyword
  41. :return: separator character
  42. """
  43. if sep == "pipe":
  44. return "|"
  45. elif sep == "comma":
  46. return ","
  47. elif sep == "space":
  48. return " "
  49. elif sep == "tab" or sep == "\\t":
  50. return "\t"
  51. elif sep == "newline" or sep == "\\n":
  52. return "\n"
  53. return sep
  54. def diff_files(filename_a, filename_b):
  55. """Diffs two text files and returns difference.
  56. :param str filename_a: first file path
  57. :param str filename_b: second file path
  58. :return: list of strings
  59. """
  60. import difflib
  61. differ = difflib.Differ()
  62. fh_a = open(filename_a, 'r')
  63. fh_b = open(filename_b, 'r')
  64. result = list(differ.compare(fh_a.readlines(),
  65. fh_b.readlines()))
  66. return result
  67. def try_remove(path):
  68. """Attempt to remove a file; no exception is generated if the
  69. attempt fails.
  70. :param str path: path to file to remove
  71. """
  72. try:
  73. os.remove(path)
  74. except:
  75. pass
  76. def try_rmdir(path):
  77. """Attempt to remove a directory; no exception is generated if the
  78. attempt fails.
  79. :param str path: path to directory to remove
  80. """
  81. try:
  82. os.rmdir(path)
  83. except:
  84. shutil.rmtree(path, ignore_errors=True)
  85. def basename(path, ext=None):
  86. """Remove leading directory components and an optional extension
  87. from the specified path
  88. :param str path: path
  89. :param str ext: extension
  90. """
  91. name = os.path.basename(path)
  92. if not ext:
  93. return name
  94. fs = name.rsplit('.', 1)
  95. if len(fs) > 1 and fs[1].lower() == ext:
  96. name = fs[0]
  97. return name
  98. class KeyValue(dict):
  99. """A general-purpose key-value store.
  100. KeyValue is a subclass of dict, but also allows entries to be read and
  101. written using attribute syntax. Example:
  102. >>> reg = KeyValue()
  103. >>> reg['north'] = 489
  104. >>> reg.north
  105. 489
  106. >>> reg.south = 205
  107. >>> reg['south']
  108. 205
  109. """
  110. def __getattr__(self, key):
  111. return self[key]
  112. def __setattr__(self, key, value):
  113. self[key] = value
  114. def parse_key_val(s, sep='=', dflt=None, val_type=None, vsep=None):
  115. """Parse a string into a dictionary, where entries are separated
  116. by newlines and the key and value are separated by `sep` (default: `=`)
  117. >>> parse_key_val('min=20\\nmax=50') == {'min': '20', 'max': '50'}
  118. True
  119. >>> parse_key_val('min=20\\nmax=50',
  120. ... val_type=float) == {'min': 20, 'max': 50}
  121. True
  122. :param str s: string to be parsed
  123. :param str sep: key/value separator
  124. :param dflt: default value to be used
  125. :param val_type: value type (None for no cast)
  126. :param vsep: vertical separator (default is Python 'universal newlines' approach)
  127. :return: parsed input (dictionary of keys/values)
  128. """
  129. result = KeyValue()
  130. if not s:
  131. return result
  132. if vsep:
  133. lines = s.split(vsep)
  134. try:
  135. lines.remove('\n')
  136. except ValueError:
  137. pass
  138. else:
  139. lines = s.splitlines()
  140. for line in lines:
  141. kv = line.split(sep, 1)
  142. k = kv[0].strip()
  143. if len(kv) > 1:
  144. v = kv[1].strip()
  145. else:
  146. v = dflt
  147. if val_type:
  148. result[k] = val_type(v)
  149. else:
  150. result[k] = v
  151. return result
  152. def decode(string):
  153. """Decode string with defualt locale
  154. :param str string: the string to decode
  155. """
  156. enc = locale.getdefaultlocale()[1]
  157. if enc:
  158. return string.decode(enc)
  159. return string
  160. def encode(string):
  161. """Encode string with defualt locale
  162. :param str string: the string to encode
  163. """
  164. enc = locale.getdefaultlocale()[1]
  165. if enc:
  166. return string.encode(enc)
  167. return string
  168. def get_num_suffix(number, max_number):
  169. """Returns formatted number with number of padding zeros
  170. depending on maximum number, used for creating suffix for data series.
  171. Does not include the suffix separator.
  172. :param number: number to be formated as map suffix
  173. :param max_number: maximum number of the series to get number of digits
  174. >>> get_num_suffix(10, 1000)
  175. '0010'
  176. >>> get_num_suffix(10, 10)
  177. '10'
  178. """
  179. return '{number:0{width}d}'.format(width=len(str(max_number)),
  180. number=number)
  181. def split(s):
  182. """!Platform specific shlex.split"""
  183. if sys.version_info >= (2, 6):
  184. return shlex.split(s, posix = (sys.platform != "win32"))
  185. elif sys.platform == "win32":
  186. return shlex.split(s.replace('\\', r'\\'))
  187. else:
  188. return shlex.split(s)