LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
fitsChanContinued.py
Go to the documentation of this file.
1 from .fitsChan import FitsChan, CardType
2 from .fitsChan import * # noqa: F403 F401
3 
4 
5 def _calc_card_pos(self, index):
6  """Convert a python index into a FitsChan position.
7 
8  Parameters
9  ----------
10  self : `FitsChan`
11  The FitsChan to index.
12  index : `int`
13  0-based index into header. If negative, counts from end.
14 
15  Raises
16  ------
17  IndexError
18  Raised if the index exceeds the size of the FitsChan. If the index
19  equals the size of the FitsChan (noting that in 0-based indexing the
20  final card is one less than the size) then this refers to the end of
21  the header.
22  """
23  # Calculate 0-based index
24  nCards = len(self)
25  if index < 0:
26  index = nCards + index
27  elif abs(index) > nCards:
28  # We allow index of one higher to indicate append
29  raise IndexError(f"Index {index} exceeds size of FitsChan ({nCards})")
30 
31  # Convert to 1-based index
32  return index + 1
33 
34 
35 def _get_current_card_value(self):
36  """Retrieve the value of the current card along with the keyword name.
37 
38  Returns
39  -------
40  name : `str`
41  The name of the current card.
42  value : `object`
43  The value in the correct Python type.
44  """
45  # Method look up table for obtaining values
46  typeLut = {CardType.INT: self.getFitsI,
47  CardType.FLOAT: self.getFitsF,
48  CardType.STRING: self.getFitsS,
49  CardType.COMPLEXF: self.getFitsCF,
50  CardType.LOGICAL: self.getFitsL
51  }
52 
53  # Get the data type for this matching card
54  ctype = self.getCardType()
55 
56  # Get the name of the card
57  name = self.getCardName()
58 
59  # Go back one card so we can ask for the value in the correct
60  # data type (getFitsX starts from the next card)
61  # thiscard = self.getCard()
62  # self.setCard(thiscard - 1)
63 
64  if ctype == CardType.UNDEF:
65  value = None
66  elif ctype in typeLut:
67  found = typeLut[ctype]("") # "" indicates current card
68  if found.found:
69  value = found.value
70  else:
71  raise RuntimeError(f"Unexpectedly failed to find card '{name}'")
72  elif ctype == CardType.COMMENT:
73  value = self.getCardComm()
74  else:
75  raise RuntimeError(f"Type, {ctype} of FITS card '{name}' not supported")
76 
77  return name, value
78 
79 
80 def length(self):
81  return self.nCard
82 
83 
84 FitsChan.__len__ = length
85 
86 
87 def iter(self):
88  """The FitsChan is its own iterator, incrementing the card position on
89  each call.
90 
91  The position of the iterator is handled internally in the FitsChan and
92  is moved to the start of the FitsChan by this call.
93  Whilst iterating do not change the internal card position.
94 
95  The iterator will return 80-character header cards.
96  """
97  self.clearCard()
98  return self
99 
100 
101 FitsChan.__iter__ = iter
102 
103 
104 def next(self):
105  """Return each 80-character header card until we run out of cards.
106  """
107  card = self.findFits("%f", True)
108  if not card.found:
109  raise StopIteration
110  return card.value
111 
112 
113 FitsChan.__next__ = next
114 
115 
116 def to_string(self):
117  """A FitsChan string representation is a FITS header with newlines
118  after each 80-character header card.
119  """
120  return "\n".join(c for c in self)
121 
122 
123 FitsChan.__str__ = to_string
124 
125 
126 def contains(self, name):
127  """Returns True if either the supplied name is present in the FitsChan
128  or the supplied integer is acceptable to the FitsChan.
129  """
130  if isinstance(name, int):
131  # index will be zero-based
132  if name >= 0 and name < self.nCard:
133  return True
134  elif isinstance(name, str):
135  currentCard = self.getCard()
136  try:
137  self.clearCard()
138  result = self.findFits(name, False)
139  finally:
140  self.setCard(currentCard)
141  if result.found:
142  return True
143 
144  return False
145 
146 
147 FitsChan.__contains__ = contains
148 
149 
150 def getitem(self, name):
151  """Return a value associated with the supplied name.
152 
153  Parameters
154  ----------
155  name : `str` or `int`
156  If the FitsChan is being accessed by integer index the returned value
157  will be the corresponding 80-character card. Index values are 0-based.
158  A negative index counts from the end of the FitsChan.
159  If the FitsChan is being accessed by string the returned value will
160  be the scalar value associated with the first card that matches the
161  supplied name.
162 
163  Returns
164  -------
165  value : `str`, `int`, `float`, `bool`, or `None`
166  The complete 80-character header card if an integer index is supplied,
167  else the first matching value of the named header.
168 
169  Raises
170  ------
171  IndexError
172  Raised if an integer index is provided and the index is out of range.
173  KeyError
174  Raised if a string is provided and that string is not present in
175  the FitsChan. Also raised if the supplied name is neither an integer
176  not a string.
177  RuntimeError
178  Raised if there is some problem accessing the value in the FitsChan.
179  """
180 
181  # Save current card position
182  currentCard = self.getCard()
183 
184  if isinstance(name, int):
185  # Calculate position in FitsChan (0-based to 1-based)
186  newpos = _calc_card_pos(self, name)
187  self.setCard(newpos)
188  try:
189  result = self.findFits("%f", False)
190  finally:
191  self.setCard(currentCard)
192  if not result.found:
193  raise IndexError(f"No FITS card at index {name}")
194  return result.value
195 
196  elif isinstance(name, str):
197 
198  try:
199  # Rewind FitsChan so we search all cards
200  self.clearCard()
201 
202  # We are only interested in the first matching card
203  result = self.findFits(name, False)
204  if not result.found:
205  raise KeyError(f"{name}'")
206 
207  this_name, value = _get_current_card_value(self)
208  if this_name != name:
209  raise RuntimeError(f"Internal inconsistency in get: {this_name} != {name}")
210 
211  finally:
212  # Reinstate the original card position
213  self.setCard(currentCard)
214 
215  return value
216 
217  raise KeyError(f"Supplied key, '{name}' of unsupported type")
218 
219 
220 FitsChan.__getitem__ = getitem
221 
222 
223 def setitem(self, name, value):
224  """Set a new value.
225 
226  Parameters
227  ----------
228  name : `str` or `int`
229  If the name is an integer index this corresponds to a position within
230  the FitsChan. Index values are 0-based. A negative index counts
231  from the end of the FitsChan. If the index matches the number of
232  cards (e.g. the return value of `len()`) the new value will be
233  appended to the end of the FitsChan.
234  If the name is an empty string or `None`, the value will be inserted
235  at the current card position as a comment card.
236  If the name is a string corresponding to a header card that is already
237  present in the FitsChan, the new value will overwrite the existing
238  value leaving the header name and any comment unchanged.
239  Any other cards matching that name later in the header will
240  be removed. If there is no header with that name, a new card will
241  be inserted at the end of the FitsChan.
242  value : `str`, `int`, `float`, `bool`, `None`
243  The new value to be inserted. If an integer index is given it must be
244  a complete FITS header card. The string will be padded to 80
245  characters.
246 
247  Raises
248  ------
249  IndexError
250  Raised if the supplied integer index is out of range.
251  KeyError
252  Raised if the supplied name is neither a string or an integer.
253  TypeError
254  Raised if an integer index is given but the supplied value is not
255  a string.
256  """
257 
258  if isinstance(name, int):
259  # Calculate position in FitsChan (0-based to 1-based)
260  newpos = _calc_card_pos(self, name)
261  self.setCard(newpos)
262 
263  if not value:
264  value = " "
265 
266  # Overwrite the entire value
267  self.putFits(value, True)
268  return
269 
270  # A blank name results in a comment card being inserted at the
271  # current position
272  if not name:
273  self.setFitsCM(value, False)
274  return
275 
276  if not isinstance(name, str):
277  raise KeyError(f"Supplied key, '{name}' of unsupported type")
278 
279  # Get current card position and rewind
280  currentCard = self.getCard()
281  try:
282  self.clearCard()
283 
284  # Look for a card with the specified name
285  # We do not care about the result, if nothing is found we will be at the
286  # end of the header
287  self.findFits(name, False)
288 
289  # pyast seems to want to delete items if the value is None but
290  # astropy and PropertyList think the key should be undefined.
291  if value is None:
292  self.setFitsU(name, overwrite=True)
293  elif isinstance(value, int):
294  self.setFitsI(name, value, overwrite=True)
295  elif isinstance(value, float):
296  self.setFitsF(name, value, overwrite=True)
297  elif isinstance(value, bool):
298  self.setFitsL(name, value, overwrite=True)
299  else:
300  # Force to string
301  self.setFitsS(name, str(value), overwrite=True)
302 
303  # Delete any later cards with matching keyword
304  while True:
305  found = self.findFits(name, False)
306  if not found.found:
307  break
308  self.delFits()
309  finally:
310  # Try to reinstate the current card
311  self.setCard(currentCard)
312 
313 
314 FitsChan.__setitem__ = setitem
315 
316 
317 def delitem(self, name):
318  """Delete an item from the FitsChan either by index (0-based) or by name.
319 
320  Parameters
321  ----------
322  name : `str` or `int`
323  If the name is an integer index the card at that position will be
324  removed. The index is zero-based. A negative index counts from the
325  end of the FitsChan.
326  If the name is a string all cards matching that name will be removed.
327 
328  Raises
329  ------
330  IndexError
331  Raised if the supplied index is out of range.
332  KeyError
333  Raised if the supplied name is not found in the FitsChan.
334  """
335  if isinstance(name, int):
336  # Correct to 1-based
337  newpos = _calc_card_pos(self, name)
338  if newpos <= 0 or newpos > self.nCard:
339  # AST will ignore this but we raise if the index is out of range
340  raise IndexError(f"No FITS card at index {name}")
341  self.setCard(newpos)
342  self.delFits()
343  return
344 
345  if not isinstance(name, str):
346  raise KeyError(f"Supplied key, '{name}' of unsupported type")
347 
348  self.clearCard()
349  # Delete any cards with matching keyword
350  deleted = False
351  while True:
352  found = self.findFits(name, False)
353  if not found.found:
354  break
355  self.delFits()
356  deleted = True
357 
358  if not deleted:
359  raise KeyError(f"No FITS card named {name}")
360 
361 
362 FitsChan.__delitem__ = delitem
363 
364 
365 def items(self):
366  """Iterate over each card, returning the keyword and value in a tuple.
367 
368  Returns
369  -------
370  key : `str`
371  The key associated with the card. Can be an empty string for some
372  comment styles. The same key name can be returned multiple times
373  and be associated with different values.
374  value : `str`, `int`, `bool`, `float`
375  The value.
376 
377  Notes
378  -----
379  The position of the iterator is internal to the FitsChan. Do not
380  change the card position when iterating.
381  """
382  self.clearCard()
383  nCards = self.nCard
384  thisCard = self.getCard()
385 
386  while thisCard <= nCards:
387  name, value = _get_current_card_value(self)
388  yield name, value
389  self.setCard(thisCard + 1)
390  thisCard = self.getCard()
391 
392 
393 FitsChan.items = items
Angle abs(Angle const &a)
Definition: Angle.h:106
def setitem(self, name, value)