utils.py 4.6 KB

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