utils.py 5.3 KB

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