OpenMPCD
Utilities.py
1 def openPossiblyCompressedFile(baseFilename):
2  """
3  Tries to return an object with file semantics for the given path, or a path
4  closely related as described below.
5 
6  When talking about `Plain` and `BZ2` instances below, what is meant is:
7  - For `python2`, `Plain` corresponds to the type `file`, and `BZ2`
8  corresponds to the type `bz2.BZ2File`.
9  - For `python3`, `Plain` and `BZ2` both correspond to `_io.TextIOWrapper`.
10 
11  If `baseFilename` ends in the string `.bz2`, a `BZ2` instance
12  is attempted to be returned in `rt` mode for that file path.
13  Otherwise, if the concatenation of `baseFilename` and the string `.bz2`
14  resolves to a file, this function tries to open it in `rt` mode and return
15  the resulting `BZ2` instance.
16  Otherwise, if `baseFilename` resolves to a file, `open` is called on it
17  with an open mode of `rt`, and that object is returned.
18  Finally, if none of the above applies, an instance of `ValueError` is
19  thrown.
20 
21  @throw IOError
22  Throws if a viable candidate is found, as described above, but the
23  file could not be opened.
24  @throw ValueError
25  Throws if no viable candidate file can be found.
26 
27  @param[in] baseFilename
28  A path to use to open a file, as described above.
29  """
30 
31  import bz2
32  import os.path
33  import sys
34 
35  if sys.version_info[0] < 3:
36  def openBZ2(path):
37  return bz2.BZ2File(path, "r")
38  else:
39  def openBZ2(path):
40  return bz2.open(path, "rt")
41 
42  if baseFilename[-4:] == '.bz2':
43  return openBZ2(baseFilename)
44 
45  if os.path.isfile(baseFilename + '.bz2'):
46  return openBZ2(baseFilename + '.bz2')
47 
48  if os.path.isfile(baseFilename):
49  return open(baseFilename, "rt")
50 
51  raise ValueError("No such file: " + baseFilename)
52 
53 
54 def readValuePairsFromFile(filename, minXValue = None):
55  """
56  Returns a `collections.OrderedDict`, containing key-value-pairs read from
57  the given file.
58 
59  The given `filename` is supplied to `openPossiblyCompressedFile`. Then,
60  each line is read. If it consists of exactly two whitespace-separated
61  sub-strings, and each can be interpreted as a `float`, let the left column,
62  interpreted as a `float`, be the key, and the right column, interpreted as
63  a `float` be the value; otherwise, the line is ignored.
64  Then, if `minXValue` is `None`, or if the key is smaller than `minXValue`
65  (as determined by the `<` operator), the key-value-pair is added to the
66  dictionary to be returned; otherwise, the line is ignored.
67 
68  Finally, after treating all lines in the file as described, the dictionary
69  is sorted by key and returned.
70 
71  @throw IOError
72  See `openPossiblyCompressedFile`.
73  @throw ValueError
74  See `openPossiblyCompressedFile`.
75  @throw ValueError
76  Throws if a key appears twice in the file (not counting ignored
77  lines).
78  """
79 
80  from collections import OrderedDict
81 
82  data = OrderedDict()
83 
84  f = openPossiblyCompressedFile(filename)
85  for line in f:
86  columns = line.split()
87  if len(columns) != 2:
88  continue
89  try:
90  x = float(columns[0])
91  y = float(columns[1])
92  except ValueError:
93  continue
94 
95  if x in data:
96  msg = "A point has been given twice in readValuePairsFromFile: "
97  msg += str(x)
98  raise ValueError(msg)
99 
100  if minXValue is not None:
101  if x < minXValue:
102  continue
103 
104  data[x] = y
105 
106  return OrderedDict(sorted(data.items()))
107 
108 def getConfigValueAndCheckConstistency(config, valueKey, knownValue):
109  """
110  Given the configuration instance `config`, fetches the value associated to
111  `valueKey` and compares it to `knownValue`.
112 
113  If `knownValue` is not `None`, it is compared to the given config's value.
114  If it does not match, an instance of `ValueError` is raised.
115 
116  @throw TypeError
117  Throws if any argument is of the wrong type.
118  @throw KeyError
119  Throws if the given `valueKey` does not exist in the given `config`.
120  @throw ValueError
121  Throws if `knownValue` is not `None`, but does not equal the given
122  config's value for the given `valueKey`.
123 
124  @param[in] config
125  An instance of `MPCDAnalysis.Configuration.Configuration`.
126  @param[in] valueKey
127  The configuration element to consider, as a `str` instance.
128  @param[in] knownValue
129  The known value for the given `valueKey`, or `None` if unknown.
130 
131  @return Returns the given config's value for the `valueKey`.
132  """
133 
134  from .Configuration import Configuration
135 
136 
137  if not isinstance(config, Configuration):
138  raise TypeError()
139  if not isinstance(valueKey, str):
140  raise TypeError()
141 
142 
143  currentValue = config[valueKey]
144 
145  if knownValue is None:
146  return currentValue
147 
148  if knownValue != currentValue:
149  msg = "Key " + valueKey + " yielded value "
150  msg += str(currentValue)
151  msg += " rather than the expeded value "
152  msg += str(knownValue)
153  raise ValueError(msg)
154 
155  return knownValue
156 
157 
158 def getConsistentConfigValue(rundirs, valueKey):
159  """
160  For the given `valueKey`, gets the configuration value for all the given
161  `rundirs` if it is consistent, and throws otherwise.
162 
163  @throw TypeError
164  Throws if any argument is of the wrong type.
165  @throw ValueError
166  Throws if not all configurations agree on the value, or the value
167  does not exist in at least one configuration.
168 
169  @param[in] rundirs
170  A `list` of `str` objects, each representing a directory from
171  which to load the file `config.txt` in an instance of
172  `MPCDAnalysis.Configuration.Configuration`.
173  @param[in] valueKey
174  The configuration key to consider, as a `str`.
175 
176  @return Returns the common value.
177  """
178 
179  from .Configuration import Configuration
180 
181 
182  if not isinstance(rundirs, list):
183  raise TypeError()
184  for rundir in rundirs:
185  if not isinstance(rundir, str):
186  raise TypeError()
187  if not isinstance(valueKey, str):
188  raise TypeError()
189 
190 
191  value = None
192 
193  try:
194  for rundir in rundirs:
195  config = Configuration(rundir + "/config.txt")
196  value = getConfigValueAndCheckConstistency(config, valueKey, value)
197  except KeyError:
198  raise ValueError()
199 
200  return value
201 
202 
203 def getNumberOfArgumentsFromCallable(f):
204  """
205  Returns the number of arguments for the given callable `f`.
206 
207  @param[in] f
208  The callable to inspect.
209  """
210 
211  import inspect
212  import sys
213 
214  if sys.version_info[0] < 3:
215  args = inspect.getargspec(f).args
216  else:
217  args = inspect.signature(f).parameters
218 
219  return len(args)