nodes: 0, module; 1, function_definition; 2, function_name:parse_leap_seconds; 3, parameters; 4, block; 5, identifier:fileobj; 6, expression_statement; 7, expression_statement; 8, for_statement; 9, expression_statement; 10, with_statement; 11, comment:# The file went out of date at the beginning of July 2016, and kept; 12, comment:# downloading every time a user ran a Skyfield program.  So we now; 13, comment:# build in a grace period:; 14, expression_statement; 15, expression_statement; 16, expression_statement; 17, expression_statement; 18, expression_statement; 19, expression_statement; 20, expression_statement; 21, expression_statement; 22, expression_statement; 23, expression_statement; 24, return_statement; 25, comment:"""Parse the IERS file ``Leap_Second.dat``.
  
      The leap dates array can be searched with::
  
          index = np.searchsorted(leap_dates, jd, 'right')
  
      The resulting index allows (TAI - UTC) to be fetched with::
  
          offset = leap_offsets[index]
  
      """; 26, assignment; 27, identifier:line; 28, identifier:lines; 29, block; 30, else_clause; 31, assignment; 32, with_clause; 33, comment:# won't help if anyone user threads are doing parsing, alas; 34, block; 35, assignment; 36, assignment; 37, assignment; 38, assignment; 39, assignment; 40, assignment; 41, assignment; 42, assignment; 43, assignment; 44, assignment; 45, expression_list; 46, identifier:lines; 47, call; 48, if_statement; 49, block; 50, identifier:line; 51, call; 52, with_item; 53, expression_statement; 54, expression_statement; 55, try_statement; 56, identifier:grace_period; 57, call; 58, identifier:expiration_date; 59, binary_operator:dt.date() + grace_period; 60, pattern_list; 61, attribute; 62, identifier:leap_dates; 63, call; 64, subscript; 65, string; 66, subscript; 67, binary_operator:mjd + 2400000.5; 68, subscript; 69, string; 70, identifier:leap_offsets; 71, call; 72, subscript; 73, assignment; 74, subscript; 75, identifier:offsets; 76, identifier:expiration_date; 77, tuple; 78, identifier:iter; 79, argument_list; 80, call; 81, block; 82, raise_statement; 83, attribute; 84, argument_list; 85, identifier:_lock; 86, assignment; 87, call; 88, block; 89, finally_clause; 90, identifier:timedelta; 91, argument_list; 92, call; 93, identifier:grace_period; 94, identifier:mjd; 95, identifier:day; 96, identifier:month; 97, identifier:year; 98, identifier:offsets; 99, call; 100, identifier:T; 101, attribute; 102, argument_list; 103, identifier:leap_dates; 104, integer:0; 105, string_content:-inf; 106, identifier:leap_dates; 107, slice; 108, identifier:mjd; 109, float:2400000.5; 110, identifier:leap_dates; 111, unary_operator; 112, string_content:inf; 113, attribute; 114, argument_list; 115, identifier:leap_offsets; 116, integer:0; 117, subscript; 118, subscript; 119, identifier:leap_offsets; 120, slice; 121, identifier:leap_dates; 122, identifier:leap_offsets; 123, identifier:fileobj; 124, attribute; 125, argument_list; 126, break_statement; 127, call; 128, identifier:line; 129, identifier:decode; 130, string; 131, identifier:original_locale; 132, call; 133, attribute; 134, argument_list; 135, expression_statement; 136, block; 137, keyword_argument; 138, attribute; 139, argument_list; 140, attribute; 141, argument_list; 142, identifier:np; 143, identifier:ndarray; 144, binary_operator:len(mjd) + 2; 145, integer:1; 146, unary_operator; 147, integer:1; 148, identifier:np; 149, identifier:ndarray; 150, binary_operator:len(mjd) + 2; 151, identifier:leap_offsets; 152, integer:1; 153, identifier:offsets; 154, integer:0; 155, integer:2; 156, identifier:line; 157, identifier:startswith; 158, string; 159, identifier:ValueError; 160, argument_list; 161, string_content:ascii; 162, attribute; 163, argument_list; 164, identifier:locale; 165, identifier:setlocale; 166, attribute; 167, string; 168, assignment; 169, expression_statement; 170, identifier:days; 171, integer:30; 172, identifier:dt; 173, identifier:date; 174, identifier:np; 175, identifier:loadtxt; 176, identifier:lines; 177, call; 178, integer:2; 179, integer:1; 180, call; 181, integer:2; 182, string_content:#  File expires on; 183, string; 184, identifier:locale; 185, identifier:setlocale; 186, attribute; 187, identifier:locale; 188, identifier:LC_ALL; 189, string_content:C; 190, identifier:dt; 191, call; 192, call; 193, identifier:len; 194, argument_list; 195, identifier:len; 196, argument_list; 197, string_content:Leap_Second.dat is missing its expiration date; 198, identifier:locale; 199, identifier:LC_ALL; 200, attribute; 201, argument_list; 202, attribute; 203, argument_list; 204, identifier:mjd; 205, identifier:mjd; 206, identifier:datetime; 207, identifier:strptime; 208, identifier:line; 209, string; 210, identifier:locale; 211, identifier:setlocale; 212, attribute; 213, identifier:original_locale; 214, string_content; 215, identifier:locale; 216, identifier:LC_ALL; 217, escape_sequence:\n
code: def parse_leap_seconds(fileobj):
      """Parse the IERS file ``Leap_Second.dat``.
  
      The leap dates array can be searched with::
  
          index = np.searchsorted(leap_dates, jd, 'right')
  
      The resulting index allows (TAI - UTC) to be fetched with::
  
          offset = leap_offsets[index]
  
      """
      lines = iter(fileobj)
      for line in lines:
          if line.startswith(b'#  File expires on'):
              break
      else:
          raise ValueError('Leap_Second.dat is missing its expiration date')
      line = line.decode('ascii')
  
      with _lock:  # won't help if anyone user threads are doing parsing, alas
          original_locale = locale.setlocale(locale.LC_ALL)
          locale.setlocale(locale.LC_ALL, 'C')
          try:
              dt = datetime.strptime(line, '#  File expires on %d %B %Y\n')
          finally:
              locale.setlocale(locale.LC_ALL, original_locale)
  
      # The file went out of date at the beginning of July 2016, and kept
      # downloading every time a user ran a Skyfield program.  So we now
      # build in a grace period:
      grace_period = timedelta(days=30)
      expiration_date = dt.date() + grace_period
      mjd, day, month, year, offsets = np.loadtxt(lines).T
      leap_dates = np.ndarray(len(mjd) + 2)
      leap_dates[0] = '-inf'
      leap_dates[1:-1] = mjd + 2400000.5
      leap_dates[-1] = 'inf'
      leap_offsets = np.ndarray(len(mjd) + 2)
      leap_offsets[0] = leap_offsets[1] = offsets[0]
      leap_offsets[2:] = offsets
      return expiration_date, (leap_dates, leap_offsets)