<s> from __future__ import division <EOL> import copy <EOL> import itertools <EOL> import re <EOL> import warnings <EOL> from collections import defaultdict <EOL> from . extern import six <EOL> from . extern . six import string_types , itervalues , iteritems , next <EOL> from . extern . six . moves import zip , range , zip_longest <EOL> from . card import Card , KEYWORD_LENGTH , _pad <EOL> from . file import _File <EOL> from . util import ( BLOCK_SIZE , isiterable , encode_ascii , decode_ascii , <EOL> fileobj_is_binary , fileobj_closed , _pad_length ) <EOL> HEADER_END_RE = re . compile ( encode_ascii ( <EOL> r'<STR_LIT>' ) ) <EOL> VALID_HEADER_CHARS = set ( chr ( x ) for x in range ( <NUM_LIT> , <NUM_LIT> ) ) <EOL> END_CARD = '<STR_LIT>' + '<STR_LIT:U+0020>' * <NUM_LIT> <EOL> class Header ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , cards = [ ] ) : <EOL> """<STR_LIT>""" <EOL> self . clear ( ) <EOL> if isinstance ( cards , Header ) : <EOL> cards = cards . cards <EOL> for card in cards : <EOL> self . append ( card , end = True ) <EOL> self . _modified = False <EOL> def __len__ ( self ) : <EOL> return len ( self . _cards ) <EOL> def __iter__ ( self ) : <EOL> for card in self . _cards : <EOL> yield card . keyword <EOL> def __contains__ ( self , keyword ) : <EOL> if keyword in self . _keyword_indices or keyword in self . _rvkc_indices : <EOL> return True <EOL> try : <EOL> self . _cardindex ( keyword ) <EOL> except ( KeyError , IndexError ) : <EOL> return False <EOL> return True <EOL> def __getitem__ ( self , key ) : <EOL> if isinstance ( key , slice ) : <EOL> return Header ( [ copy . copy ( c ) for c in self . _cards [ key ] ] ) <EOL> elif self . _haswildcard ( key ) : <EOL> return Header ( [ copy . copy ( self . _cards [ idx ] ) <EOL> for idx in self . _wildcardmatch ( key ) ] ) <EOL> elif ( isinstance ( key , string_types ) and <EOL> key . upper ( ) in Card . _commentary_keywords ) : <EOL> key = key . upper ( ) <EOL> return _HeaderCommentaryCards ( self , key ) <EOL> if isinstance ( key , tuple ) : <EOL> keyword = key [ <NUM_LIT:0> ] <EOL> else : <EOL> keyword = key <EOL> card = self . _cards [ self . _cardindex ( key ) ] <EOL> if card . field_specifier is not None and keyword == card . rawkeyword : <EOL> return card . rawvalue <EOL> return card . value <EOL> def __setitem__ ( self , key , value ) : <EOL> if self . _set_slice ( key , value , self ) : <EOL> return <EOL> if isinstance ( value , tuple ) : <EOL> if not ( <NUM_LIT:0> < len ( value ) <= <NUM_LIT:2> ) : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> if len ( value ) == <NUM_LIT:1> : <EOL> value , comment = value [ <NUM_LIT:0> ] , None <EOL> if value is None : <EOL> value = '<STR_LIT>' <EOL> elif len ( value ) == <NUM_LIT:2> : <EOL> value , comment = value <EOL> if value is None : <EOL> value = '<STR_LIT>' <EOL> if comment is None : <EOL> comment = '<STR_LIT>' <EOL> else : <EOL> comment = None <EOL> card = None <EOL> if isinstance ( key , int ) : <EOL> card = self . _cards [ key ] <EOL> elif isinstance ( key , tuple ) : <EOL> card = self . _cards [ self . _cardindex ( key ) ] <EOL> if card : <EOL> card . value = value <EOL> if comment is not None : <EOL> card . comment = comment <EOL> if card . _modified : <EOL> self . _modified = True <EOL> else : <EOL> self . _update ( ( key , value , comment ) ) <EOL> def __delitem__ ( self , key ) : <EOL> if isinstance ( key , slice ) or self . _haswildcard ( key ) : <EOL> if isinstance ( key , slice ) : <EOL> indices = range ( * key . indices ( len ( self ) ) ) <EOL> if key . step and key . step < <NUM_LIT:0> : <EOL> indices = reversed ( indices ) <EOL> else : <EOL> indices = self . _wildcardmatch ( key ) <EOL> for idx in reversed ( indices ) : <EOL> del self [ idx ] <EOL> return <EOL> elif isinstance ( key , string_types ) : <EOL> key = Card . normalize_keyword ( key ) <EOL> indices = self . _keyword_indices <EOL> if key not in self . _keyword_indices : <EOL> indices = self . _rvkc_indices <EOL> if key not in indices : <EOL> raise KeyError ( "<STR_LIT>" % key ) <EOL> for idx in reversed ( indices [ key ] ) : <EOL> del self [ idx ] <EOL> return <EOL> idx = self . _cardindex ( key ) <EOL> card = self . _cards [ idx ] <EOL> keyword = card . keyword <EOL> del self . _cards [ idx ] <EOL> indices = self . _keyword_indices [ keyword ] <EOL> indices . remove ( idx ) <EOL> if not indices : <EOL> del self . _keyword_indices [ keyword ] <EOL> if card . field_specifier is not None : <EOL> indices = self . _rvkc_indices [ card . rawkeyword ] <EOL> indices . remove ( idx ) <EOL> if not indices : <EOL> del self . _rvkc_indices [ card . rawkeyword ] <EOL> self . _updateindices ( idx , increment = False ) <EOL> self . _modified = True <EOL> def __repr__ ( self ) : <EOL> return self . tostring ( sep = '<STR_LIT:\n>' , endcard = False , padding = False ) <EOL> def __str__ ( self ) : <EOL> return self . tostring ( ) <EOL> def __eq__ ( self , other ) : <EOL> """<STR_LIT>""" <EOL> return str ( self ) == str ( other ) <EOL> def __add__ ( self , other ) : <EOL> temp = self . copy ( strip = False ) <EOL> temp . extend ( other ) <EOL> return temp <EOL> def __iadd__ ( self , other ) : <EOL> self . extend ( other ) <EOL> return self <EOL> @ property <EOL> def cards ( self ) : <EOL> """<STR_LIT>""" <EOL> return _CardAccessor ( self ) <EOL> @ property <EOL> def comments ( self ) : <EOL> """<STR_LIT>""" <EOL> return _HeaderComments ( self ) <EOL> @ property <EOL> def _modified ( self ) : <EOL> """<STR_LIT>""" <EOL> modified_cards = any ( c . _modified for c in self . _cards ) <EOL> if modified_cards : <EOL> self . __dict__ [ '<STR_LIT>' ] = True <EOL> return self . __dict__ [ '<STR_LIT>' ] <EOL> @ _modified . setter <EOL> def _modified ( self , val ) : <EOL> self . __dict__ [ '<STR_LIT>' ] = val <EOL> @ classmethod <EOL> def fromstring ( cls , data , sep = '<STR_LIT>' ) : <EOL> """<STR_LIT>""" <EOL> cards = [ ] <EOL> require_full_cardlength = set ( sep ) . issubset ( VALID_HEADER_CHARS ) <EOL> idx = <NUM_LIT:0> <EOL> image = [ ] <EOL> while idx < len ( data ) : <EOL> if require_full_cardlength : <EOL> end_idx = idx + Card . length <EOL> else : <EOL> try : <EOL> end_idx = data . index ( sep , idx ) <EOL> except ValueError : <EOL> end_idx = len ( data ) <EOL> next_image = data [ idx : end_idx ] <EOL> idx = end_idx + len ( sep ) <EOL> if image : <EOL> if next_image [ : <NUM_LIT:8> ] == '<STR_LIT>' : <EOL> image . append ( next_image ) <EOL> continue <EOL> cards . append ( Card . fromstring ( '<STR_LIT>' . join ( image ) ) ) <EOL> if require_full_cardlength : <EOL> if next_image == END_CARD : <EOL> image = [ ] <EOL> break <EOL> else : <EOL> if next_image . split ( sep ) [ <NUM_LIT:0> ] . rstrip ( ) == '<STR_LIT>' : <EOL> image = [ ] <EOL> break <EOL> image = [ next_image ] <EOL> if image : <EOL> cards . append ( Card . fromstring ( '<STR_LIT>' . join ( image ) ) ) <EOL> return cls ( cards ) <EOL> @ classmethod <EOL> def fromfile ( cls , fileobj , sep = '<STR_LIT>' , endcard = True , padding = True ) : <EOL> """<STR_LIT>""" <EOL> close_file = False <EOL> if isinstance ( fileobj , string_types ) : <EOL> fileobj = open ( fileobj , '<STR_LIT:r>' ) <EOL> close_file = True <EOL> try : <EOL> is_binary = fileobj_is_binary ( fileobj ) <EOL> def block_iter ( nbytes ) : <EOL> while True : <EOL> data = fileobj . read ( nbytes ) <EOL> if data : <EOL> yield data <EOL> else : <EOL> break <EOL> return cls . _from_blocks ( block_iter , is_binary , sep , endcard , <EOL> padding ) [ <NUM_LIT:1> ] <EOL> finally : <EOL> if close_file : <EOL> fileobj . close ( ) <EOL> @ classmethod <EOL> def _from_blocks ( cls , block_iter , is_binary , sep , endcard , padding ) : <EOL> """<STR_LIT>""" <EOL> actual_block_size = _block_size ( sep ) <EOL> clen = Card . length + len ( sep ) <EOL> blocks = block_iter ( actual_block_size ) <EOL> try : <EOL> block = next ( blocks ) <EOL> except StopIteration : <EOL> raise EOFError ( ) <EOL> if not is_binary : <EOL> block = encode_ascii ( block ) <EOL> read_blocks = [ ] <EOL> is_eof = False <EOL> end_found = False <EOL> while True : <EOL> end_found , block = cls . _find_end_card ( block , clen ) <EOL> read_blocks . append ( decode_ascii ( block ) ) <EOL> if end_found : <EOL> break <EOL> try : <EOL> block = next ( blocks ) <EOL> except StopIteration : <EOL> is_eof = True <EOL> break <EOL> if not block : <EOL> is_eof = True <EOL> break <EOL> if not is_binary : <EOL> block = encode_ascii ( block ) <EOL> if not end_found and is_eof and endcard : <EOL> raise IOError ( '<STR_LIT>' ) <EOL> header_str = '<STR_LIT>' . join ( read_blocks ) <EOL> if header_str and header_str [ - <NUM_LIT:1> ] == '<STR_LIT>' : <EOL> if is_eof and header_str . strip ( '<STR_LIT>' ) == '<STR_LIT>' : <EOL> warnings . warn ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> raise EOFError ( ) <EOL> else : <EOL> warnings . warn ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> header_str . replace ( '<STR_LIT>' , '<STR_LIT:U+0020>' ) <EOL> if padding and ( len ( header_str ) % actual_block_size ) != <NUM_LIT:0> : <EOL> actual_len = len ( header_str ) - actual_block_size + BLOCK_SIZE <EOL> raise ValueError ( '<STR_LIT>' <EOL> % ( BLOCK_SIZE , actual_len ) ) <EOL> return header_str , cls . fromstring ( header_str , sep = sep ) <EOL> @ classmethod <EOL> def _find_end_card ( cls , block , card_len ) : <EOL> """<STR_LIT>""" <EOL> for mo in HEADER_END_RE . finditer ( block ) : <EOL> if mo . start ( ) % card_len != <NUM_LIT:0> : <EOL> continue <EOL> if mo . group ( '<STR_LIT>' ) : <EOL> offset = mo . start ( ) <EOL> trailing = block [ offset + <NUM_LIT:3> : offset + card_len - <NUM_LIT:3> ] . rstrip ( ) <EOL> if trailing : <EOL> trailing = repr ( trailing ) . lstrip ( '<STR_LIT>' ) <EOL> warnings . warn ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % <EOL> trailing ) <EOL> else : <EOL> warnings . warn ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % <EOL> BLOCK_SIZE ) <EOL> block = ( block [ : offset ] + encode_ascii ( END_CARD ) + <EOL> block [ offset + len ( END_CARD ) : ] ) <EOL> return True , block <EOL> return False , block <EOL> def tostring ( self , sep = '<STR_LIT>' , endcard = True , padding = True ) : <EOL> r"""<STR_LIT>""" <EOL> lines = [ ] <EOL> for card in self . _cards : <EOL> s = str ( card ) <EOL> while s : <EOL> lines . append ( s [ : Card . length ] ) <EOL> s = s [ Card . length : ] <EOL> s = sep . join ( lines ) <EOL> if endcard : <EOL> s += sep + _pad ( '<STR_LIT>' ) <EOL> if padding : <EOL> s += '<STR_LIT:U+0020>' * _pad_length ( len ( s ) ) <EOL> return s <EOL> def tofile ( self , fileobj , sep = '<STR_LIT>' , endcard = True , padding = True , <EOL> clobber = False ) : <EOL> r"""<STR_LIT>""" <EOL> close_file = fileobj_closed ( fileobj ) <EOL> if not isinstance ( fileobj , _File ) : <EOL> fileobj = _File ( fileobj , mode = '<STR_LIT>' , clobber = clobber ) <EOL> try : <EOL> blocks = self . tostring ( sep = sep , endcard = endcard , padding = padding ) <EOL> actual_block_size = _block_size ( sep ) <EOL> if padding and len ( blocks ) % actual_block_size != <NUM_LIT:0> : <EOL> raise IOError ( '<STR_LIT>' <EOL> '<STR_LIT>' % <EOL> ( len ( blocks ) - actual_block_size + BLOCK_SIZE , <EOL> BLOCK_SIZE ) ) <EOL> if not fileobj . simulateonly : <EOL> fileobj . flush ( ) <EOL> try : <EOL> offset = fileobj . tell ( ) <EOL> except ( AttributeError , IOError ) : <EOL> offset = <NUM_LIT:0> <EOL> fileobj . write ( blocks . encode ( '<STR_LIT:ascii>' ) ) <EOL> fileobj . flush ( ) <EOL> finally : <EOL> if close_file : <EOL> fileobj . close ( ) <EOL> @ classmethod <EOL> def fromtextfile ( cls , fileobj , endcard = False ) : <EOL> """<STR_LIT>""" <EOL> return cls . fromfile ( fileobj , sep = '<STR_LIT:\n>' , endcard = endcard , padding = False ) <EOL> def totextfile ( self , fileobj , endcard = False , clobber = False ) : <EOL> """<STR_LIT>""" <EOL> self . tofile ( fileobj , sep = '<STR_LIT:\n>' , endcard = endcard , padding = False , <EOL> clobber = clobber ) <EOL> def clear ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _cards = [ ] <EOL> self . _keyword_indices = defaultdict ( list ) <EOL> self . _rvkc_indices = defaultdict ( list ) <EOL> def copy ( self , strip = False ) : <EOL> """<STR_LIT>""" <EOL> tmp = Header ( [ copy . copy ( card ) for card in self . _cards ] ) <EOL> if strip : <EOL> tmp . _strip ( ) <EOL> return tmp <EOL> @ classmethod <EOL> def fromkeys ( cls , iterable , value = None ) : <EOL> """<STR_LIT>""" <EOL> d = cls ( ) <EOL> if not isinstance ( value , tuple ) : <EOL> value = ( value , ) <EOL> for key in iterable : <EOL> d . append ( ( key , ) + value ) <EOL> return d <EOL> def get ( self , key , default = None ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> return self [ key ] <EOL> except ( KeyError , IndexError ) : <EOL> return default <EOL> def set ( self , keyword , value = None , comment = None , before = None , after = None , <EOL> savecomment = False ) : <EOL> """<STR_LIT>""" <EOL> if ( len ( keyword ) <= KEYWORD_LENGTH and <EOL> Card . _keywd_FSC_RE . match ( keyword ) and <EOL> keyword not in self . _keyword_indices ) : <EOL> new_card = Card ( keyword , value , comment ) <EOL> new_keyword = new_card . keyword <EOL> else : <EOL> new_keyword = keyword <EOL> if ( new_keyword not in Card . _commentary_keywords and <EOL> new_keyword in self ) : <EOL> if comment is None or savecomment : <EOL> comment = self . comments [ keyword ] <EOL> if value is None : <EOL> value = self [ keyword ] <EOL> self [ keyword ] = ( value , comment ) <EOL> if before is not None or after is not None : <EOL> card = self . _cards [ self . _cardindex ( keyword ) ] <EOL> self . _relativeinsert ( card , before = before , after = after , <EOL> replace = True ) <EOL> elif before is not None or after is not None : <EOL> self . _relativeinsert ( ( keyword , value , comment ) , before = before , <EOL> after = after ) <EOL> else : <EOL> self [ keyword ] = ( value , comment ) <EOL> def items ( self ) : <EOL> """<STR_LIT>""" <EOL> return list ( self . iteritems ( ) ) <EOL> def iteritems ( self ) : <EOL> """<STR_LIT>""" <EOL> for card in self . _cards : <EOL> yield ( card . keyword , card . value ) <EOL> def iterkeys ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . __iter__ ( ) <EOL> def itervalues ( self ) : <EOL> """<STR_LIT>""" <EOL> for _ , v in iteritems ( self ) : <EOL> yield v <EOL> def keys ( self ) : <EOL> """<STR_LIT>""" <EOL> return [ keyword for keyword in self ] <EOL> def pop ( self , * args ) : <EOL> """<STR_LIT>""" <EOL> if len ( args ) > <NUM_LIT:2> : <EOL> raise TypeError ( '<STR_LIT>' <EOL> '<STR_LIT>' % len ( args ) ) <EOL> if len ( args ) == <NUM_LIT:0> : <EOL> key = - <NUM_LIT:1> <EOL> else : <EOL> key = args [ <NUM_LIT:0> ] <EOL> try : <EOL> value = self [ key ] <EOL> except ( KeyError , IndexError ) : <EOL> if len ( args ) == <NUM_LIT:2> : <EOL> return args [ <NUM_LIT:1> ] <EOL> raise <EOL> del self [ key ] <EOL> return value <EOL> def popitem ( self ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> k , v = next ( iteritems ( self ) ) <EOL> except StopIteration : <EOL> raise KeyError ( '<STR_LIT>' ) <EOL> del self [ k ] <EOL> return k , v <EOL> def setdefault ( self , key , default = None ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> return self [ key ] <EOL> except ( KeyError , IndexError ) : <EOL> self [ key ] = default <EOL> return default <EOL> def update ( self , * args , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> if args : <EOL> other = args [ <NUM_LIT:0> ] <EOL> else : <EOL> other = None <EOL> def update_from_dict ( k , v ) : <EOL> if not isinstance ( v , tuple ) : <EOL> card = Card ( k , v ) <EOL> elif <NUM_LIT:0> < len ( v ) <= <NUM_LIT:2> : <EOL> card = Card ( * ( ( k , ) + v ) ) <EOL> else : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % k ) <EOL> self . _update ( card ) <EOL> if other is None : <EOL> pass <EOL> elif hasattr ( other , '<STR_LIT>' ) : <EOL> for k , v in other . iteritems ( ) : <EOL> update_from_dict ( k , v ) <EOL> elif hasattr ( other , '<STR_LIT>' ) : <EOL> for k in other . keys ( ) : <EOL> update_from_dict ( k , other [ k ] ) <EOL> else : <EOL> for idx , card in enumerate ( other ) : <EOL> if isinstance ( card , Card ) : <EOL> self . _update ( card ) <EOL> elif isinstance ( card , tuple ) and ( <NUM_LIT:1> < len ( card ) <= <NUM_LIT:3> ) : <EOL> self . _update ( Card ( * card ) ) <EOL> else : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % idx ) <EOL> if kwargs : <EOL> self . update ( kwargs ) <EOL> def values ( self ) : <EOL> """<STR_LIT>""" <EOL> return [ v for _ , v in iteritems ( self ) ] <EOL> def append ( self , card = None , useblanks = True , bottom = False , end = False ) : <EOL> """<STR_LIT>""" <EOL> if isinstance ( card , string_types ) : <EOL> card = Card ( card ) <EOL> elif isinstance ( card , tuple ) : <EOL> card = Card ( * card ) <EOL> elif card is None : <EOL> card = Card ( ) <EOL> elif not isinstance ( card , Card ) : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % card ) <EOL> if not end and card . is_blank : <EOL> end = True <EOL> if end : <EOL> self . _cards . append ( card ) <EOL> idx = len ( self . _cards ) - <NUM_LIT:1> <EOL> else : <EOL> idx = len ( self . _cards ) - <NUM_LIT:1> <EOL> while idx >= <NUM_LIT:0> and self . _cards [ idx ] . is_blank : <EOL> idx -= <NUM_LIT:1> <EOL> if not bottom and card . keyword not in Card . _commentary_keywords : <EOL> while ( idx >= <NUM_LIT:0> and <EOL> self . _cards [ idx ] . keyword in Card . _commentary_keywords ) : <EOL> idx -= <NUM_LIT:1> <EOL> idx += <NUM_LIT:1> <EOL> self . _cards . insert ( idx , card ) <EOL> self . _updateindices ( idx ) <EOL> keyword = Card . normalize_keyword ( card . keyword ) <EOL> self . _keyword_indices [ keyword ] . append ( idx ) <EOL> if card . field_specifier is not None : <EOL> self . _rvkc_indices [ card . rawkeyword ] . append ( idx ) <EOL> if not end : <EOL> if not bottom and card . keyword in Card . _commentary_keywords : <EOL> self . _keyword_indices [ keyword ] . sort ( ) <EOL> if useblanks and self . _countblanks ( ) : <EOL> self . _useblanks ( len ( str ( card ) ) // Card . length ) <EOL> self . _modified = True <EOL> def extend ( self , cards , strip = True , unique = False , update = False , <EOL> update_first = False , useblanks = True , bottom = False , end = False ) : <EOL> """<STR_LIT>""" <EOL> temp = Header ( cards ) <EOL> if strip : <EOL> temp . _strip ( ) <EOL> if len ( self ) : <EOL> first = self . cards [ <NUM_LIT:0> ] . keyword <EOL> else : <EOL> first = None <EOL> extend_cards = [ ] <EOL> for idx , card in enumerate ( temp . cards ) : <EOL> keyword = card . keyword <EOL> if keyword not in Card . _commentary_keywords : <EOL> if unique and not update and keyword in self : <EOL> continue <EOL> elif update : <EOL> if idx == <NUM_LIT:0> and update_first : <EOL> if ( ( keyword == '<STR_LIT>' and first == '<STR_LIT>' ) or <EOL> ( keyword == '<STR_LIT>' and first == '<STR_LIT>' ) ) : <EOL> del self [ <NUM_LIT:0> ] <EOL> self . insert ( <NUM_LIT:0> , card ) <EOL> else : <EOL> self [ keyword ] = ( card . value , card . comment ) <EOL> elif keyword in self : <EOL> self [ keyword ] = ( card . value , card . comment ) <EOL> else : <EOL> extend_cards . append ( card ) <EOL> else : <EOL> extend_cards . append ( card ) <EOL> else : <EOL> if ( unique or update ) and keyword in self : <EOL> if card . is_blank : <EOL> extend_cards . append ( card ) <EOL> continue <EOL> for value in self [ keyword ] : <EOL> if value == card . value : <EOL> break <EOL> else : <EOL> extend_cards . append ( card ) <EOL> else : <EOL> extend_cards . append ( card ) <EOL> for card in extend_cards : <EOL> self . append ( card , useblanks = useblanks , bottom = bottom , end = end ) <EOL> def count ( self , keyword ) : <EOL> """<STR_LIT>""" <EOL> keyword = Card . normalize_keyword ( keyword ) <EOL> if keyword not in self . _keyword_indices : <EOL> raise KeyError ( "<STR_LIT>" % keyword ) <EOL> return len ( self . _keyword_indices [ keyword ] ) <EOL> def index ( self , keyword , start = None , stop = None ) : <EOL> """<STR_LIT>""" <EOL> if start is None : <EOL> start = <NUM_LIT:0> <EOL> if stop is None : <EOL> stop = len ( self . _cards ) <EOL> if stop < start : <EOL> step = - <NUM_LIT:1> <EOL> else : <EOL> step = <NUM_LIT:1> <EOL> norm_keyword = Card . normalize_keyword ( keyword ) <EOL> for idx in range ( start , stop , step ) : <EOL> if self . _cards [ idx ] . keyword . upper ( ) == norm_keyword : <EOL> return idx <EOL> else : <EOL> raise ValueError ( '<STR_LIT>' % keyword ) <EOL> def insert ( self , key , card , useblanks = True , after = False ) : <EOL> """<STR_LIT>""" <EOL> if not isinstance ( key , int ) : <EOL> idx = self . _cardindex ( key ) <EOL> else : <EOL> idx = key <EOL> if after : <EOL> if idx == - <NUM_LIT:1> : <EOL> idx = len ( self . _cards ) <EOL> else : <EOL> idx += <NUM_LIT:1> <EOL> if idx >= len ( self . _cards ) : <EOL> self . append ( card , end = True ) <EOL> return <EOL> if isinstance ( card , string_types ) : <EOL> card = Card ( card ) <EOL> elif isinstance ( card , tuple ) : <EOL> card = Card ( * card ) <EOL> elif not isinstance ( card , Card ) : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % card ) <EOL> self . _cards . insert ( idx , card ) <EOL> keyword = card . keyword <EOL> if idx < <NUM_LIT:0> : <EOL> idx += len ( self . _cards ) - <NUM_LIT:1> <EOL> if idx < <NUM_LIT:0> : <EOL> idx = <NUM_LIT:0> <EOL> self . _updateindices ( idx ) <EOL> self . _keyword_indices [ keyword ] . append ( idx ) <EOL> count = len ( self . _keyword_indices [ keyword ] ) <EOL> if count > <NUM_LIT:1> : <EOL> if keyword not in Card . _commentary_keywords : <EOL> warnings . warn ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % keyword ) <EOL> self . _keyword_indices [ keyword ] . sort ( ) <EOL> if card . field_specifier is not None : <EOL> rvkc_indices = self . _rvkc_indices [ card . rawkeyword ] <EOL> rvkc_indices . append ( idx ) <EOL> rvkc_indices . sort ( ) <EOL> if useblanks : <EOL> self . _useblanks ( len ( str ( card ) ) // Card . length ) <EOL> self . _modified = True <EOL> def remove ( self , keyword ) : <EOL> """<STR_LIT>""" <EOL> del self [ self . index ( keyword ) ] <EOL> def rename_keyword ( self , oldkeyword , newkeyword , force = False ) : <EOL> """<STR_LIT>""" <EOL> oldkeyword = Card . normalize_keyword ( oldkeyword ) <EOL> newkeyword = Card . normalize_keyword ( newkeyword ) <EOL> if newkeyword == '<STR_LIT>' : <EOL> raise ValueError ( '<STR_LIT>' ) <EOL> if ( newkeyword in Card . _commentary_keywords or <EOL> oldkeyword in Card . _commentary_keywords ) : <EOL> if not ( newkeyword in Card . _commentary_keywords and <EOL> oldkeyword in Card . _commentary_keywords ) : <EOL> raise ValueError ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> elif not force and newkeyword in self : <EOL> raise ValueError ( '<STR_LIT>' <EOL> % newkeyword ) <EOL> idx = self . index ( oldkeyword ) <EOL> card = self . cards [ idx ] <EOL> del self [ idx ] <EOL> self . insert ( idx , ( newkeyword , card . value , card . comment ) ) <EOL> def add_history ( self , value , before = None , after = None ) : <EOL> """<STR_LIT>""" <EOL> self . _add_commentary ( '<STR_LIT>' , value , before = before , after = after ) <EOL> def add_comment ( self , value , before = None , after = None ) : <EOL> """<STR_LIT>""" <EOL> self . _add_commentary ( '<STR_LIT>' , value , before = before , after = after ) <EOL> def add_blank ( self , value = '<STR_LIT>' , before = None , after = None ) : <EOL> """<STR_LIT>""" <EOL> self . _add_commentary ( '<STR_LIT>' , value , before = before , after = after ) <EOL> def _update ( self , card ) : <EOL> """<STR_LIT>""" <EOL> keyword , value , comment = card <EOL> keyword = keyword . upper ( ) <EOL> if keyword . startswith ( '<STR_LIT>' ) : <EOL> keyword = keyword [ <NUM_LIT:9> : ] <EOL> if ( keyword not in Card . _commentary_keywords and <EOL> keyword in self . _keyword_indices ) : <EOL> idx = self . _keyword_indices [ keyword ] [ <NUM_LIT:0> ] <EOL> existing_card = self . _cards [ idx ] <EOL> existing_card . value = value <EOL> if comment is not None : <EOL> existing_card . comment = comment <EOL> if existing_card . _modified : <EOL> self . _modified = True <EOL> elif keyword in Card . _commentary_keywords : <EOL> cards = self . _splitcommentary ( keyword , value ) <EOL> if keyword in self . _keyword_indices : <EOL> idx = self . index ( keyword , start = len ( self ) - <NUM_LIT:1> , stop = - <NUM_LIT:1> ) <EOL> isblank = not ( keyword or value or comment ) <EOL> for c in reversed ( cards ) : <EOL> self . insert ( idx + <NUM_LIT:1> , c , useblanks = ( not isblank ) ) <EOL> else : <EOL> for c in cards : <EOL> self . append ( c , bottom = True ) <EOL> else : <EOL> self . append ( card ) <EOL> def _cardindex ( self , key ) : <EOL> """<STR_LIT>""" <EOL> if isinstance ( key , string_types ) : <EOL> keyword = key <EOL> n = <NUM_LIT:0> <EOL> elif isinstance ( key , int ) : <EOL> if key < <NUM_LIT:0> : <EOL> key += len ( self . _cards ) <EOL> if key < <NUM_LIT:0> or key >= len ( self . _cards ) : <EOL> raise IndexError ( '<STR_LIT>' ) <EOL> return key <EOL> elif isinstance ( key , slice ) : <EOL> return key <EOL> elif isinstance ( key , tuple ) : <EOL> if ( len ( key ) != <NUM_LIT:2> or not isinstance ( key [ <NUM_LIT:0> ] , string_types ) or <EOL> not isinstance ( key [ <NUM_LIT:1> ] , int ) ) : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> keyword , n = key <EOL> else : <EOL> raise ValueError ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> keyword = Card . normalize_keyword ( keyword ) <EOL> indices = self . _keyword_indices . get ( keyword , None ) <EOL> if keyword and not indices : <EOL> if len ( keyword ) > KEYWORD_LENGTH or '<STR_LIT:.>' in keyword : <EOL> raise KeyError ( "<STR_LIT>" % keyword ) <EOL> else : <EOL> indices = self . _rvkc_indices . get ( keyword , None ) <EOL> if not indices : <EOL> raise KeyError ( "<STR_LIT>" % keyword ) <EOL> try : <EOL> return indices [ n ] <EOL> except IndexError : <EOL> raise IndexError ( '<STR_LIT>' % <EOL> ( len ( indices ) , keyword ) ) <EOL> def _keyword_from_index ( self , idx ) : <EOL> """<STR_LIT>""" <EOL> if idx < <NUM_LIT:0> : <EOL> idx += len ( self . _cards ) - <NUM_LIT:1> <EOL> keyword = self . _cards [ idx ] . keyword <EOL> repeat = self . _keyword_indices [ keyword ] . index ( idx ) <EOL> return keyword , repeat <EOL> def _relativeinsert ( self , card , before = None , after = None , replace = False ) : <EOL> """<STR_LIT>""" <EOL> if before is None : <EOL> insertionkey = after <EOL> else : <EOL> insertionkey = before <EOL> def get_insertion_idx ( ) : <EOL> if not ( isinstance ( insertionkey , int ) and <EOL> insertionkey >= len ( self . _cards ) ) : <EOL> idx = self . _cardindex ( insertionkey ) <EOL> else : <EOL> idx = insertionkey <EOL> if before is None : <EOL> idx += <NUM_LIT:1> <EOL> return idx <EOL> if replace : <EOL> old_idx = self . _cardindex ( card . keyword ) <EOL> insertion_idx = get_insertion_idx ( ) <EOL> if ( insertion_idx >= len ( self . _cards ) and <EOL> old_idx == len ( self . _cards ) - <NUM_LIT:1> ) : <EOL> return <EOL> if before is not None : <EOL> if old_idx == insertion_idx - <NUM_LIT:1> : <EOL> return <EOL> elif after is not None and old_idx == insertion_idx : <EOL> return <EOL> del self [ old_idx ] <EOL> idx = get_insertion_idx ( ) <EOL> if card [ <NUM_LIT:0> ] in Card . _commentary_keywords : <EOL> cards = reversed ( self . _splitcommentary ( card [ <NUM_LIT:0> ] , card [ <NUM_LIT:1> ] ) ) <EOL> else : <EOL> cards = [ card ] <EOL> for c in cards : <EOL> self . insert ( idx , c ) <EOL> def _updateindices ( self , idx , increment = True ) : <EOL> """<STR_LIT>""" <EOL> if idx > len ( self . _cards ) : <EOL> return <EOL> increment = <NUM_LIT:1> if increment else - <NUM_LIT:1> <EOL> for index_sets in ( self . _keyword_indices , self . _rvkc_indices ) : <EOL> for indices in itervalues ( index_sets ) : <EOL> for jdx , keyword_index in enumerate ( indices ) : <EOL> if keyword_index >= idx : <EOL> indices [ jdx ] += increment <EOL> def _countblanks ( self ) : <EOL> """<STR_LIT>""" <EOL> for idx in range ( <NUM_LIT:1> , len ( self . _cards ) ) : <EOL> if not self . _cards [ - idx ] . is_blank : <EOL> return idx - <NUM_LIT:1> <EOL> return <NUM_LIT:0> <EOL> def _useblanks ( self , count ) : <EOL> for _ in range ( count ) : <EOL> if self . _cards [ - <NUM_LIT:1> ] . is_blank : <EOL> del self [ - <NUM_LIT:1> ] <EOL> else : <EOL> break <EOL> def _haswildcard ( self , keyword ) : <EOL> """<STR_LIT>""" <EOL> return ( isinstance ( keyword , string_types ) and <EOL> ( keyword . endswith ( '<STR_LIT>' ) or '<STR_LIT:*>' in keyword or '<STR_LIT:?>' in keyword ) ) <EOL> def _wildcardmatch ( self , pattern ) : <EOL> """<STR_LIT>""" <EOL> pattern = pattern . replace ( '<STR_LIT:*>' , r'<STR_LIT>' ) . replace ( '<STR_LIT:?>' , r'<STR_LIT:.>' ) <EOL> pattern = pattern . replace ( '<STR_LIT>' , r'<STR_LIT>' ) + '<STR_LIT:$>' <EOL> pattern_re = re . compile ( pattern , re . I ) <EOL> return [ idx for idx , card in enumerate ( self . _cards ) <EOL> if pattern_re . match ( card . keyword ) ] <EOL> def _set_slice ( self , key , value , target ) : <EOL> """<STR_LIT>""" <EOL> if isinstance ( key , slice ) or self . _haswildcard ( key ) : <EOL> if isinstance ( key , slice ) : <EOL> indices = range ( * key . indices ( len ( target ) ) ) <EOL> else : <EOL> indices = self . _wildcardmatch ( key ) <EOL> if isinstance ( value , string_types ) or not isiterable ( value ) : <EOL> value = itertools . repeat ( value , len ( indices ) ) <EOL> for idx , val in zip ( indices , value ) : <EOL> target [ idx ] = val <EOL> return True <EOL> return False <EOL> def _splitcommentary ( self , keyword , value ) : <EOL> """<STR_LIT>""" <EOL> maxlen = Card . length - KEYWORD_LENGTH <EOL> valuestr = str ( value ) <EOL> if len ( valuestr ) <= maxlen : <EOL> cards = [ Card ( keyword , value ) ] <EOL> else : <EOL> idx = <NUM_LIT:0> <EOL> cards = [ ] <EOL> while idx < len ( valuestr ) : <EOL> cards . append ( Card ( keyword , valuestr [ idx : idx + maxlen ] ) ) <EOL> idx += maxlen <EOL> return cards <EOL> def _strip ( self ) : <EOL> """<STR_LIT>""" <EOL> if '<STR_LIT>' in self : <EOL> naxis = self [ '<STR_LIT>' ] <EOL> else : <EOL> naxis = <NUM_LIT:0> <EOL> if '<STR_LIT>' in self : <EOL> tfields = self [ '<STR_LIT>' ] <EOL> else : <EOL> tfields = <NUM_LIT:0> <EOL> for idx in range ( naxis ) : <EOL> try : <EOL> del self [ '<STR_LIT>' + str ( idx + <NUM_LIT:1> ) ] <EOL> except KeyError : <EOL> pass <EOL> for name in ( '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) : <EOL> for idx in range ( tfields ) : <EOL> try : <EOL> del self [ name + str ( idx + <NUM_LIT:1> ) ] <EOL> except KeyError : <EOL> pass <EOL> for name in ( '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' ) : <EOL> try : <EOL> del self [ name ] <EOL> except KeyError : <EOL> pass <EOL> def _add_commentary ( self , key , value , before = None , after = None ) : <EOL> """<STR_LIT>""" <EOL> if before is not None or after is not None : <EOL> self . _relativeinsert ( ( key , value ) , before = before , <EOL> after = after ) <EOL> else : <EOL> self [ key ] = value <EOL> if six . PY3 : <EOL> keys = iterkeys <EOL> values = itervalues <EOL> items = iteritems <EOL> del iterkeys <EOL> del itervalues <EOL> del iteritems <EOL> class _CardAccessor ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , header ) : <EOL> self . _header = header <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT:\n>' . join ( repr ( c ) for c in self . _header . _cards ) <EOL> def __len__ ( self ) : <EOL> return len ( self . _header . _cards ) <EOL> def __iter__ ( self ) : <EOL> return iter ( self . _header . _cards ) <EOL> def __eq__ ( self , other ) : <EOL> if not isiterable ( other ) or isinstance ( other , string_types ) : <EOL> if len ( self ) == <NUM_LIT:1> : <EOL> other = [ other ] <EOL> else : <EOL> return False <EOL> for a , b in zip_longest ( self , other ) : <EOL> if a != b : <EOL> return False <EOL> else : <EOL> return True <EOL> def __ne__ ( self , other ) : <EOL> return not ( self == other ) <EOL> def __getitem__ ( self , item ) : <EOL> if isinstance ( item , slice ) or self . _header . _haswildcard ( item ) : <EOL> return self . __class__ ( self . _header [ item ] ) <EOL> idx = self . _header . _cardindex ( item ) <EOL> return self . _header . _cards [ idx ] <EOL> class _HeaderComments ( _CardAccessor ) : <EOL> """<STR_LIT>""" <EOL> def __iter__ ( self ) : <EOL> for card in self . _header . _cards : <EOL> yield card . comment <EOL> def __repr__ ( self ) : <EOL> """<STR_LIT>""" <EOL> keyword_length = KEYWORD_LENGTH <EOL> for card in self . _header . _cards : <EOL> keyword_length = max ( keyword_length , len ( card . keyword ) ) <EOL> return '<STR_LIT:\n>' . join ( '<STR_LIT>' % ( keyword_length , c . keyword , c . comment ) <EOL> for c in self . _header . _cards ) <EOL> def __getitem__ ( self , item ) : <EOL> """<STR_LIT>""" <EOL> item = super ( _HeaderComments , self ) . __getitem__ ( item ) <EOL> if isinstance ( item , _HeaderComments ) : <EOL> return item <EOL> return item . comment <EOL> def __setitem__ ( self , item , comment ) : <EOL> """<STR_LIT>""" <EOL> if self . _header . _set_slice ( item , comment , self ) : <EOL> return <EOL> idx = self . _header . _cardindex ( item ) <EOL> value = self . _header [ idx ] <EOL> self . _header [ idx ] = ( value , comment ) <EOL> class _HeaderCommentaryCards ( _CardAccessor ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , header , keyword = '<STR_LIT>' ) : <EOL> super ( _HeaderCommentaryCards , self ) . __init__ ( header ) <EOL> self . _keyword = keyword <EOL> self . _count = self . _header . count ( self . _keyword ) <EOL> self . _indices = slice ( self . _count ) . indices ( self . _count ) <EOL> def __len__ ( self ) : <EOL> return len ( range ( * self . _indices ) ) <EOL> def __iter__ ( self ) : <EOL> for idx in range ( * self . _indices ) : <EOL> yield self . _header [ ( self . _keyword , idx ) ] <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT:\n>' . join ( self ) <EOL> def __getitem__ ( self , idx ) : <EOL> if isinstance ( idx , slice ) : <EOL> n = self . __class__ ( self . _header , self . _keyword ) <EOL> n . _indices = idx . indices ( self . _count ) <EOL> return n <EOL> elif not isinstance ( idx , int ) : <EOL> raise ValueError ( '<STR_LIT>' % self . _keyword ) <EOL> idx = list ( range ( * self . _indices ) ) [ idx ] <EOL> return self . _header [ ( self . _keyword , idx ) ] <EOL> def __setitem__ ( self , item , value ) : <EOL> """<STR_LIT>""" <EOL> if self . _header . _set_slice ( item , value , self ) : <EOL> return <EOL> self . _header [ ( self . _keyword , item ) ] = value <EOL> def _block_size ( sep ) : <EOL> """<STR_LIT>""" <EOL> return BLOCK_SIZE + ( len ( sep ) * ( BLOCK_SIZE // Card . length - <NUM_LIT:1> ) ) </s>
