signature:
def _dec_to_bin ( ip ) :
    """Decimal to binary conversion ."""

implementation:
bits = [ ]
while ip :
    bits . append ( _BYTES_TO_BITS [ ip & 255 ] )
    ip >>= 8
bits . reverse ( )
return '' . join ( bits ) or 32 * '0'


signature:
def _dec_to_dec_long ( ip , check = True ) :
    """Decimal to decimal ( long ) conversion ."""

implementation:
if check and not is_dec ( ip ) :
    raise ValueError ( '_dec_to_dec: invalid IP: "%s"' % ip )
return int ( str ( ip ) )


signature:
def _bits_to_dec ( nm , check = True ) :
    """Bits to decimal conversion ."""

implementation:
if check and not is_bits_nm ( nm ) :
    raise ValueError ( '_bits_to_dec: invalid netmask: "%s"' % nm )
bits = int ( str ( nm ) )
return VALID_NETMASKS [ bits ]


signature:
def _wildcard_to_dec ( nm , check = False ) :
    """Wildcard bits to decimal conversion ."""

implementation:
if check and not is_wildcard_nm ( nm ) :
    raise ValueError ( '_wildcard_to_dec: invalid netmask: "%s"' % nm )
return 0xFFFFFFFF - _dot_to_dec ( nm , check = False )


signature:
def _is_notation ( ip , notation , _isnm ) :
    """Internally used to check if an IP / netmask is in the given notation ."""

implementation:
notation_orig = notation
notation = _get_notation ( notation )
if notation not in _CHECK_FUNCT_KEYS :
    raise ValueError ( '_is_notation: unkown notation: "%s"' % notation_orig )
return _CHECK_FUNCT [ notation ] [ _isnm ] ( ip )


signature:
def _detect ( ip , _isnm ) :
    """Function internally used to detect the notation of the
 given IP or netmask ."""

implementation:
ip = str ( ip )
if len ( ip ) > 1 :
    if ip [ 0 : 2 ] == '0x' :
        if _CHECK_FUNCT [ IP_HEX ] [ _isnm ] ( ip ) :
            return IP_HEX
    elif ip [ 0 ] == '0' :
        if _CHECK_FUNCT [ IP_OCT ] [ _isnm ] ( ip ) :
            return IP_OCT
if _CHECK_FUNCT [ IP_DOT ] [ _isnm ] ( ip ) :
    return IP_DOT
elif _isnm and _CHECK_FUNCT [ NM_BITS ] [ _isnm ] ( ip ) :
    return NM_BITS
elif _CHECK_FUNCT [ IP_DEC ] [ _isnm ] ( ip ) :
    return IP_DEC
elif _isnm and _CHECK_FUNCT [ NM_WILDCARD ] [ _isnm ] ( ip ) :
    return NM_WILDCARD
elif _CHECK_FUNCT [ IP_BIN ] [ _isnm ] ( ip ) :
    return IP_BIN
return IP_UNKNOWN


signature:
def _convert ( ip , notation , inotation , _check , _isnm ) :
    """Internally used to convert IPs and netmasks to other notations ."""

implementation:
inotation_orig = inotation
notation_orig = notation
inotation = _get_notation ( inotation )
notation = _get_notation ( notation )
if inotation is None :
    raise ValueError ( '_convert: unknown input notation: "%s"' % inotation_orig )
if notation is None :
    raise ValueError ( '_convert: unknown output notation: "%s"' % notation_orig )
docheck = _check or False
if inotation == IP_UNKNOWN :
    inotation = _detect ( ip , _isnm )
    if inotation == IP_UNKNOWN :
        raise ValueError ( '_convert: unable to guess input notation or invalid value' )
    if _check is None :
        docheck = True
# We _ always _ check this case later .
if _isnm :
    docheck = False
dec = 0
if inotation == IP_DOT :
    dec = _dot_to_dec ( ip , docheck )
elif inotation == IP_HEX :
    dec = _hex_to_dec ( ip , docheck )
elif inotation == IP_BIN :
    dec = _bin_to_dec ( ip , docheck )
elif inotation == IP_OCT :
    dec = _oct_to_dec ( ip , docheck )
elif inotation == IP_DEC :
    dec = _dec_to_dec_long ( ip , docheck )
elif _isnm and inotation == NM_BITS :
    dec = _bits_to_dec ( ip , docheck )
elif _isnm and inotation == NM_WILDCARD :
    dec = _wildcard_to_dec ( ip , docheck )
else :
    raise ValueError ( '_convert: unknown IP/netmask notation: "%s"' % inotation_orig )
# Ensure this is a valid netmask .
if _isnm and dec not in _NETMASKS_VALUES :
    raise ValueError ( '_convert: invalid netmask: "%s"' % ip )
if notation == IP_DOT :
    return _dec_to_dot ( dec )
elif notation == IP_HEX :
    return _dec_to_hex ( dec )
elif notation == IP_BIN :
    return _dec_to_bin ( dec )
elif notation == IP_OCT :
    return _dec_to_oct ( dec )
elif notation == IP_DEC :
    return _dec_to_dec_str ( dec )
elif _isnm and notation == NM_BITS :
    return _dec_to_bits ( dec )
elif _isnm and notation == NM_WILDCARD :
    return _dec_to_wildcard ( dec )
else :
    raise ValueError ( 'convert: unknown notation: "%s"' % notation_orig )


signature:
def convert ( ip , notation = IP_DOT , inotation = IP_UNKNOWN , check = True ) :
    """Convert among IP address notations .
 Given an IP address , this function returns the address
 in another notation .
 @ param ip : the IP address .
 @ type ip : integers , strings or object with an appropriate _ _ str ( ) _ _ method .
 @ param notation : the notation of the output ( default : IP _ DOT ) .
 @ type notation : one of the IP _ * constants , or the equivalent strings .
 @ param inotation : force the input to be considered in the given notation
 ( default the notation of the input is autodetected ) .
 @ type inotation : one of the IP _ * constants , or the equivalent strings .
 @ param check : force the notation check on the input .
 @ type check : True force the check , False force not to check and None
 do the check only if the inotation is unknown .
 @ return : a string representing the IP in the selected notation .
 @ raise ValueError : raised when the input is in unknown notation ."""

implementation: return _convert ( ip , notation , inotation , _check = check , _isnm = False )


signature:
def convert_nm ( nm , notation = IP_DOT , inotation = IP_UNKNOWN , check = True ) :
    """Convert a netmask to another notation ."""

implementation: return _convert ( nm , notation , inotation , _check = check , _isnm = True )


signature:
def set ( self , ip , notation = IP_UNKNOWN ) :
    """Set the IP address / netmask ."""

implementation:
self . _ip_dec = int ( _convert ( ip , notation = IP_DEC , inotation = notation , _check = True , _isnm = self . _isnm ) )
self . _ip = _convert ( self . _ip_dec , notation = IP_DOT , inotation = IP_DEC , _check = False , _isnm = self . _isnm )


signature:
def get_hex ( self ) :
    """Return the hexadecimal notation of the address / netmask ."""

implementation: return _convert ( self . _ip_dec , notation = IP_HEX , inotation = IP_DEC , _check = False , _isnm = self . _isnm )


signature:
def get_bin ( self ) :
    """Return the binary notation of the address / netmask ."""

implementation: return _convert ( self . _ip_dec , notation = IP_BIN , inotation = IP_DEC , _check = False , _isnm = self . _isnm )


signature:
def get_oct ( self ) :
    """Return the octal notation of the address / netmask ."""

implementation: return _convert ( self . _ip_dec , notation = IP_OCT , inotation = IP_DEC , _check = False , _isnm = self . _isnm )


signature:
def _cmp_prepare ( self , other ) :
    """Prepare the item to be compared with this address / netmask ."""

implementation:
if isinstance ( other , self . __class__ ) :
    return other . _ip_dec
elif isinstance ( other , int ) : # NOTE : this hides the fact that " other " can be a non valid IP / nm .
    return other
return self . __class__ ( other ) . _ip_dec


signature:
def _add ( self , other ) :
    """Sum two IP addresses ."""

implementation:
if isinstance ( other , self . __class__ ) :
    sum_ = self . _ip_dec + other . _ip_dec
elif isinstance ( other , int ) :
    sum_ = self . _ip_dec + other
else :
    other = self . __class__ ( other )
    sum_ = self . _ip_dec + other . _ip_dec
return sum_


signature:
def _sub ( self , other ) :
    """Subtract two IP addresses ."""

implementation:
if isinstance ( other , self . __class__ ) :
    sub = self . _ip_dec - other . _ip_dec
if isinstance ( other , int ) :
    sub = self . _ip_dec - other
else :
    other = self . __class__ ( other )
    sub = self . _ip_dec - other . _ip_dec
return sub


signature:
def get_bits ( self ) :
    """Return the bits notation of the netmask ."""

implementation: return _convert ( self . _ip , notation = NM_BITS , inotation = IP_DOT , _check = False , _isnm = self . _isnm )


signature:
def get_wildcard ( self ) :
    """Return the wildcard bits notation of the netmask ."""

implementation: return _convert ( self . _ip , notation = NM_WILDCARD , inotation = IP_DOT , _check = False , _isnm = self . _isnm )


signature:
def set ( self , ip , netmask = None ) :
    """Set the IP address and the netmask ."""

implementation:
if isinstance ( ip , str ) and netmask is None :
    ipnm = ip . split ( '/' )
    if len ( ipnm ) != 2 :
        raise ValueError ( 'set: invalid CIDR: "%s"' % ip )
    ip = ipnm [ 0 ]
    netmask = ipnm [ 1 ]
if isinstance ( ip , IPv4Address ) :
    self . _ip = ip
else :
    self . _ip = IPv4Address ( ip )
if isinstance ( netmask , IPv4NetMask ) :
    self . _nm = netmask
else :
    self . _nm = IPv4NetMask ( netmask )
ipl = int ( self . _ip )
nml = int ( self . _nm )
base_add = ipl & nml
self . _ip_num = 0xFFFFFFFF - 1 - nml
# NOTE : quite a mess .
# This ' s here to handle / 32 ( - 1 ) and / 31 ( 0 ) netmasks .
if self . _ip_num in ( - 1 , 0 ) :
    if self . _ip_num == - 1 :
        self . _ip_num = 1
    else :
        self . _ip_num = 2
    self . _net_ip = None
    self . _bc_ip = None
    self . _first_ip_dec = base_add
    self . _first_ip = IPv4Address ( self . _first_ip_dec , notation = IP_DEC )
    if self . _ip_num == 1 :
        last_ip_dec = self . _first_ip_dec
    else :
        last_ip_dec = self . _first_ip_dec + 1
    self . _last_ip = IPv4Address ( last_ip_dec , notation = IP_DEC )
    return
self . _net_ip = IPv4Address ( base_add , notation = IP_DEC )
self . _bc_ip = IPv4Address ( base_add + self . _ip_num + 1 , notation = IP_DEC )
self . _first_ip_dec = base_add + 1
self . _first_ip = IPv4Address ( self . _first_ip_dec , notation = IP_DEC )
self . _last_ip = IPv4Address ( base_add + self . _ip_num , notation = IP_DEC )


signature:
def set_ip ( self , ip ) :
    """Change the current IP ."""

implementation: self . set ( ip = ip , netmask = self . _nm )


signature:
def set_netmask ( self , netmask ) :
    """Change the current netmask ."""

implementation: self . set ( ip = self . _ip , netmask = netmask )


signature:
def is_valid_ip ( self , ip ) :
    """Return true if the given address in amongst the usable addresses ,
 or if the given CIDR is contained in this one ."""

implementation:
if not isinstance ( ip , ( IPv4Address , CIDR ) ) :
    if str ( ip ) . find ( '/' ) == - 1 :
        ip = IPv4Address ( ip )
    else : # Support for CIDR strings / objects , an idea of Nicola Novello .
        ip = CIDR ( ip )
if isinstance ( ip , IPv4Address ) :
    if ip < self . _first_ip or ip > self . _last_ip :
        return False
elif isinstance ( ip , CIDR ) : # NOTE : manage / 31 networks ; 127.0.0.1/31 is considered to
# be included in 127.0.0.1/8.
    if ip . _nm . _ip_dec == 0xFFFFFFFE and self . _nm . _ip_dec != 0xFFFFFFFE :
        compare_to_first = self . _net_ip . _ip_dec
        compare_to_last = self . _bc_ip . _ip_dec
    else :
        compare_to_first = self . _first_ip . _ip_dec
        compare_to_last = self . _last_ip . _ip_dec
    if ip . _first_ip . _ip_dec < compare_to_first or ip . _last_ip . _ip_dec > compare_to_last :
        return False
return True


signature:
async def upload_file ( self , bucket , file , uploadpath = None , key = None , ContentType = None , ** kw ) :
    """Upload a file to S3 possibly using the multi - part uploader
 Return the key uploaded"""

implementation:
is_filename = False
if hasattr ( file , 'read' ) :
    if hasattr ( file , 'seek' ) :
        file . seek ( 0 )
    file = file . read ( )
    size = len ( file )
elif key :
    size = len ( file )
else :
    is_filename = True
    size = os . stat ( file ) . st_size
    key = os . path . basename ( file )
assert key , 'key not available'
if not ContentType :
    ContentType , _ = mimetypes . guess_type ( key )
if uploadpath :
    if not uploadpath . endswith ( '/' ) :
        uploadpath = '%s/' % uploadpath
    key = '%s%s' % ( uploadpath , key )
params = dict ( Bucket = bucket , Key = key )
if not ContentType :
    ContentType = 'application/octet-stream'
params [ 'ContentType' ] = ContentType
if size > MULTI_PART_SIZE and is_filename :
    resp = await _multipart ( self , file , params )
elif is_filename :
    with open ( file , 'rb' ) as fp :
        params [ 'Body' ] = fp . read ( )
    resp = await self . put_object ( ** params )
else :
    params [ 'Body' ] = file
    resp = await self . put_object ( ** params )
if 'Key' not in resp :
    resp [ 'Key' ] = key
if 'Bucket' not in resp :
    resp [ 'Bucket' ] = bucket
return resp


signature:
async def copy_storage_object ( self , source_bucket , source_key , bucket , key ) :
    """Copy a file from one bucket into another"""

implementation:
info = await self . head_object ( Bucket = source_bucket , Key = source_key )
size = info [ 'ContentLength' ]
if size > MULTI_PART_SIZE :
    result = await _multipart_copy ( self , source_bucket , source_key , bucket , key , size )
else :
    result = await self . copy_object ( Bucket = bucket , Key = key , CopySource = _source_string ( source_bucket , source_key ) )
return result


signature:
def upload_folder ( self , bucket , folder , key = None , skip = None , content_types = None ) :
    """Recursively upload a ` ` folder ` ` into a backet .
 : param bucket : bucket where to upload the folder to
 : param folder : the folder location in the local file system
 : param key : Optional key where the folder is uploaded
 : param skip : Optional list of files to skip
 : param content _ types : Optional dictionary mapping suffixes to
 content types
 : return : a coroutine"""

implementation:
uploader = FolderUploader ( self , bucket , folder , key , skip , content_types )
return uploader . start ( )


signature:
async def _upload_file ( self , full_path ) :
    """Coroutine for uploading a single file"""

implementation:
rel_path = os . path . relpath ( full_path , self . folder )
key = s3_key ( os . path . join ( self . key , rel_path ) )
ct = self . content_types . get ( key . split ( '.' ) [ - 1 ] )
with open ( full_path , 'rb' ) as fp :
    file = fp . read ( )
try :
    await self . botocore . upload_file ( self . bucket , file , key = key , ContentType = ct )
except Exception as exc :
    LOGGER . error ( 'Could not upload "%s": %s' , key , exc )
    self . failures [ key ] = self . all . pop ( full_path )
    return
size = self . all . pop ( full_path )
self . success [ key ] = size
self . total_size += size
percentage = 100 * ( 1 - len ( self . all ) / self . total_files )
message = '{0:.0f}% completed - uploaded "{1}" - {2}' . format ( percentage , key , convert_bytes ( size ) )
LOGGER . info ( message )


signature:
def get_paginator ( self , operation_name ) :
    """Create a paginator for an operation .
 : type operation _ name : string
 : param operation _ name : The operation name . This is the same name
 as the method name on the client . For example , if the
 method name is ` ` create _ foo ` ` , and you ' d normally invoke the
 operation as ` ` client . create _ foo ( * * kwargs ) ` ` , if the
 ` ` create _ foo ` ` operation can be paginated , you can use the
 call ` ` client . get _ paginator ( " create _ foo " ) ` ` .
 : raise OperationNotPageableError : Raised if the operation is not
 pageable . You can use the ` ` client . can _ paginate ` ` method to
 check if an operation is pageable .
 : rtype : L { botocore . paginate . Paginator }
 : return : A paginator object ."""

implementation:
if not self . can_paginate ( operation_name ) :
    raise OperationNotPageableError ( operation_name = operation_name )
else :
    actual_operation_name = self . _PY_TO_OP_NAME [ operation_name ]
    # substitute iterator with async one
    Paginator . PAGE_ITERATOR_CLS = AsyncPageIterator
    paginator = Paginator ( getattr ( self , operation_name ) , self . _cache [ 'page_config' ] [ actual_operation_name ] )
    return paginator


signature:
async def trigger ( self , event , data = None , socket_id = None ) :
    '''Trigger an ` ` event ` ` on this channel'''

implementation:
json_data = json . dumps ( data , cls = self . pusher . encoder )
query_string = self . signed_query ( event , json_data , socket_id )
signed_path = "%s?%s" % ( self . path , query_string )
pusher = self . pusher
absolute_url = pusher . get_absolute_path ( signed_path )
response = await pusher . http . post ( absolute_url , data = json_data , headers = [ ( 'Content-Type' , 'application/json' ) ] )
response . raise_for_status ( )
return response . status_code == 202


signature:
async def connect ( self ) :
    '''Connect to a Pusher websocket'''

implementation:
if not self . _consumer :
    waiter = self . _waiter = asyncio . Future ( )
    try :
        address = self . _websocket_host ( )
        self . logger . info ( 'Connect to %s' , address )
        self . _consumer = await self . http . get ( address )
        if self . _consumer . status_code != 101 :
            raise PusherError ( "Could not connect to websocket" )
    except Exception as exc :
        waiter . set_exception ( exc )
        raise
    else :
        await waiter
return self . _consumer


signature:
def on_message ( self , websocket , message ) :
    '''Handle websocket incoming messages'''

implementation:
waiter = self . _waiter
self . _waiter = None
encoded = json . loads ( message )
event = encoded . get ( 'event' )
channel = encoded . get ( 'channel' )
data = json . loads ( encoded . get ( 'data' ) )
try :
    if event == PUSHER_ERROR :
        raise PusherError ( data [ 'message' ] , data [ 'code' ] )
    elif event == PUSHER_CONNECTION :
        self . socket_id = data . get ( 'socket_id' )
        self . logger . info ( 'Succesfully connected on socket %s' , self . socket_id )
        waiter . set_result ( self . socket_id )
    elif event == PUSHER_SUBSCRIBED :
        self . logger . info ( 'Succesfully subscribed to %s' , encoded . get ( 'channel' ) )
    elif channel :
        self [ channel ] . _event ( event , data )
except Exception as exc :
    if waiter :
        waiter . set_exception ( exc )
    else :
        self . logger . exception ( 'pusher error' )


signature:
def urlsafe_nopadding_b64decode ( data ) :
    '''URL safe Base64 decode without padding ( = )'''

implementation:
padding = len ( data ) % 4
if padding != 0 :
    padding = 4 - padding
padding = '=' * padding
data = data + padding
return urlsafe_b64decode ( data )


signature:
def const_equal ( str_a , str_b ) :
    '''Constant time string comparison'''

implementation:
if len ( str_a ) != len ( str_b ) :
    return False
result = True
for i in range ( len ( str_a ) ) :
    result &= ( str_a [ i ] == str_b [ i ] )
return result


signature:
def decode_html_entities ( html ) :
    """Decodes a limited set of HTML entities ."""

implementation:
if not html :
    return html
for entity , char in six . iteritems ( html_entity_map ) :
    html = html . replace ( entity , char )
return html


signature:
def set_signature_passphrases ( self , signature_passphrases ) :
    '''Set signature passphrases'''

implementation: self . signature_passphrases = self . _update_dict ( signature_passphrases , { } , replace_data = True )


signature:
def set_encryption_passphrases ( self , encryption_passphrases ) :
    '''Set encryption passphrases'''

implementation: self . encryption_passphrases = self . _update_dict ( encryption_passphrases , { } , replace_data = True )


signature:
def set_algorithms ( self , signature = None , encryption = None , serialization = None , compression = None ) :
    '''Set algorithms used for sealing . Defaults can not be overridden .'''

implementation:
self . signature_algorithms = self . _update_dict ( signature , self . DEFAULT_SIGNATURE )
self . encryption_algorithms = self . _update_dict ( encryption , self . DEFAULT_ENCRYPTION )
self . serialization_algorithms = self . _update_dict ( serialization , self . DEFAULT_SERIALIZATION )
self . compression_algorithms = self . _update_dict ( compression , self . DEFAULT_COMPRESSION )


signature:
def get_algorithms ( self ) :
    '''Get algorithms used for sealing'''

implementation: return { 'signature' : self . signature_algorithms , 'encryption' : self . encryption_algorithms , 'serialization' : self . serialization_algorithms , 'compression' : self . compression_algorithms , }


signature:
def _set_options ( self , options ) :
    '''Private function for setting options used for sealing'''

implementation:
if not options :
    return self . options . copy ( )
options = options . copy ( )
if 'magic' in options :
    self . set_magic ( options [ 'magic' ] )
    del ( options [ 'magic' ] )
if 'flags' in options :
    flags = options [ 'flags' ]
    del ( options [ 'flags' ] )
    for key , value in flags . iteritems ( ) :
        if not isinstance ( value , bool ) :
            raise TypeError ( 'Invalid flag type for: %s' % key )
else :
    flags = self . options [ 'flags' ]
if 'info' in options :
    del ( options [ 'info' ] )
for key , value in options . iteritems ( ) :
    if not isinstance ( value , int ) :
        raise TypeError ( 'Invalid option type for: %s' % key )
    if value < 0 or value > 255 :
        raise ValueError ( 'Option value out of range for: %s' % key )
new_options = self . options . copy ( )
new_options . update ( options )
new_options [ 'flags' ] . update ( flags )
return new_options


signature:
def set_magic ( self , magic ) :
    '''Set magic ( prefix )'''

implementation:
if magic is None or isinstance ( magic , str ) :
    self . magic = magic
else :
    raise TypeError ( 'Invalid value for magic' )


signature:
def seal ( self , data , options = None ) :
    '''Seal data'''

implementation:
options = self . _set_options ( options )
data = self . _serialize_data ( data , options )
data = self . _compress_data ( data , options )
data = self . _encrypt_data ( data , options )
data = self . _add_header ( data , options )
data = self . _add_magic ( data )
data = self . _sign_data ( data , options )
data = self . _remove_magic ( data )
data = urlsafe_nopadding_b64encode ( data )
data = self . _add_magic ( data )
return data


signature:
def unseal ( self , data , return_options = False ) :
    '''Unseal data'''

implementation:
data = self . _remove_magic ( data )
data = urlsafe_nopadding_b64decode ( data )
options = self . _read_header ( data )
data = self . _add_magic ( data )
data = self . _unsign_data ( data , options )
data = self . _remove_magic ( data )
data = self . _remove_header ( data , options )
data = self . _decrypt_data ( data , options )
data = self . _decompress_data ( data , options )
data = self . _unserialize_data ( data , options )
if return_options :
    return data , options
else :
    return data


signature:
def verify_signature ( self , data ) :
    '''Verify sealed data signature'''

implementation:
data = self . _remove_magic ( data )
data = urlsafe_nopadding_b64decode ( data )
options = self . _read_header ( data )
data = self . _add_magic ( data )
self . _unsign_data ( data , options )


signature:
def _encode ( self , data , algorithm , key = None ) :
    '''Encode data with specific algorithm'''

implementation:
if algorithm [ 'type' ] == 'hmac' :
    return data + self . _hmac_generate ( data , algorithm , key )
elif algorithm [ 'type' ] == 'aes' :
    return self . _aes_encrypt ( data , algorithm , key )
elif algorithm [ 'type' ] == 'no-serialization' :
    return data
elif algorithm [ 'type' ] == 'json' :
    return json . dumps ( data )
elif algorithm [ 'type' ] == 'no-compression' :
    return data
elif algorithm [ 'type' ] == 'gzip' :
    return self . _zlib_compress ( data , algorithm )
else :
    raise Exception ( 'Algorithm not supported: %s' % algorithm [ 'type' ] )


signature:
def _decode ( self , data , algorithm , key = None ) :
    '''Decode data with specific algorithm'''

implementation:
if algorithm [ 'type' ] == 'hmac' :
    verify_signature = data [ - algorithm [ 'hash_size' ] : ]
    data = data [ : - algorithm [ 'hash_size' ] ]
    signature = self . _hmac_generate ( data , algorithm , key )
    if not const_equal ( verify_signature , signature ) :
        raise Exception ( 'Invalid signature' )
    return data
elif algorithm [ 'type' ] == 'aes' :
    return self . _aes_decrypt ( data , algorithm , key )
elif algorithm [ 'type' ] == 'no-serialization' :
    return data
elif algorithm [ 'type' ] == 'json' :
    return json . loads ( data )
elif algorithm [ 'type' ] == 'no-compression' :
    return data
elif algorithm [ 'type' ] == 'gzip' :
    return self . _zlib_decompress ( data , algorithm )
else :
    raise Exception ( 'Algorithm not supported: %s' % algorithm [ 'type' ] )


signature:
def _sign_data ( self , data , options ) :
    '''Add signature to data'''

implementation:
if options [ 'signature_algorithm_id' ] not in self . signature_algorithms :
    raise Exception ( 'Unknown signature algorithm id: %d' % options [ 'signature_algorithm_id' ] )
signature_algorithm = self . signature_algorithms [ options [ 'signature_algorithm_id' ] ]
algorithm = self . _get_algorithm_info ( signature_algorithm )
key_salt = get_random_bytes ( algorithm [ 'salt_size' ] )
key = self . _generate_key ( options [ 'signature_passphrase_id' ] , self . signature_passphrases , key_salt , algorithm )
data = self . _encode ( data , algorithm , key )
return data + key_salt


signature:
def _unsign_data ( self , data , options ) :
    '''Verify and remove signature'''

implementation:
if options [ 'signature_algorithm_id' ] not in self . signature_algorithms :
    raise Exception ( 'Unknown signature algorithm id: %d' % options [ 'signature_algorithm_id' ] )
signature_algorithm = self . signature_algorithms [ options [ 'signature_algorithm_id' ] ]
algorithm = self . _get_algorithm_info ( signature_algorithm )
key_salt = ''
if algorithm [ 'salt_size' ] :
    key_salt = data [ - algorithm [ 'salt_size' ] : ]
    data = data [ : - algorithm [ 'salt_size' ] ]
key = self . _generate_key ( options [ 'signature_passphrase_id' ] , self . signature_passphrases , key_salt , algorithm )
data = self . _decode ( data , algorithm , key )
return data


signature:
def _encrypt_data ( self , data , options ) :
    '''Encrypt data'''

implementation:
if options [ 'encryption_algorithm_id' ] not in self . encryption_algorithms :
    raise Exception ( 'Unknown encryption algorithm id: %d' % options [ 'encryption_algorithm_id' ] )
encryption_algorithm = self . encryption_algorithms [ options [ 'encryption_algorithm_id' ] ]
algorithm = self . _get_algorithm_info ( encryption_algorithm )
key_salt = get_random_bytes ( algorithm [ 'salt_size' ] )
key = self . _generate_key ( options [ 'encryption_passphrase_id' ] , self . encryption_passphrases , key_salt , algorithm )
data = self . _encode ( data , algorithm , key )
return data + key_salt


signature:
def _decrypt_data ( self , data , options ) :
    '''Decrypt data'''

implementation:
if options [ 'encryption_algorithm_id' ] not in self . encryption_algorithms :
    raise Exception ( 'Unknown encryption algorithm id: %d' % options [ 'encryption_algorithm_id' ] )
encryption_algorithm = self . encryption_algorithms [ options [ 'encryption_algorithm_id' ] ]
algorithm = self . _get_algorithm_info ( encryption_algorithm )
key_salt = ''
if algorithm [ 'salt_size' ] :
    key_salt = data [ - algorithm [ 'salt_size' ] : ]
    data = data [ : - algorithm [ 'salt_size' ] ]
key = self . _generate_key ( options [ 'encryption_passphrase_id' ] , self . encryption_passphrases , key_salt , algorithm )
data = self . _decode ( data , algorithm , key )
return data


signature:
def _serialize_data ( self , data , options ) :
    '''Serialize data'''

implementation:
serialization_algorithm_id = options [ 'serialization_algorithm_id' ]
if serialization_algorithm_id not in self . serialization_algorithms :
    raise Exception ( 'Unknown serialization algorithm id: %d' % serialization_algorithm_id )
serialization_algorithm = self . serialization_algorithms [ serialization_algorithm_id ]
algorithm = self . _get_algorithm_info ( serialization_algorithm )
data = self . _encode ( data , algorithm )
return data


signature:
def _unserialize_data ( self , data , options ) :
    '''Unserialize data'''

implementation:
serialization_algorithm_id = options [ 'serialization_algorithm_id' ]
if serialization_algorithm_id not in self . serialization_algorithms :
    raise Exception ( 'Unknown serialization algorithm id: %d' % serialization_algorithm_id )
serialization_algorithm = self . serialization_algorithms [ serialization_algorithm_id ]
algorithm = self . _get_algorithm_info ( serialization_algorithm )
data = self . _decode ( data , algorithm )
return data


signature:
def _compress_data ( self , data , options ) :
    '''Compress data'''

implementation:
compression_algorithm_id = options [ 'compression_algorithm_id' ]
if compression_algorithm_id not in self . compression_algorithms :
    raise Exception ( 'Unknown compression algorithm id: %d' % compression_algorithm_id )
compression_algorithm = self . compression_algorithms [ compression_algorithm_id ]
algorithm = self . _get_algorithm_info ( compression_algorithm )
compressed = self . _encode ( data , algorithm )
if len ( compressed ) < len ( data ) :
    data = compressed
else :
    options [ 'compression_algorithm_id' ] = 0
return data


signature:
def _decompress_data ( self , data , options ) :
    '''Decompress data'''

implementation:
compression_algorithm_id = options [ 'compression_algorithm_id' ]
if compression_algorithm_id not in self . compression_algorithms :
    raise Exception ( 'Unknown compression algorithm id: %d' % compression_algorithm_id )
compression_algorithm = self . compression_algorithms [ compression_algorithm_id ]
algorithm = self . _get_algorithm_info ( compression_algorithm )
data = self . _decode ( data , algorithm )
return data


signature:
def _remove_magic ( self , data ) :
    '''Verify and remove magic'''

implementation:
if not self . magic :
    return data
magic_size = len ( self . magic )
magic = data [ : magic_size ]
if magic != self . magic :
    raise Exception ( 'Invalid magic' )
data = data [ magic_size : ]
return data


signature:
def _add_header ( self , data , options ) :
    '''Add header to data'''

implementation:
# pylint : disable = W0142
version_info = self . _get_version_info ( options [ 'version' ] )
flags = options [ 'flags' ]
header_flags = dict ( ( i , str ( int ( j ) ) ) for i , j in options [ 'flags' ] . iteritems ( ) )
header_flags = '' . join ( version_info [ 'flags' ] ( ** header_flags ) )
header_flags = int ( header_flags , 2 )
options [ 'flags' ] = header_flags
header = version_info [ 'header' ]
header = header ( ** options )
header = pack ( version_info [ 'header_format' ] , * header )
if 'timestamp' in flags and flags [ 'timestamp' ] :
    timestamp = long ( time ( ) )
    timestamp = pack ( version_info [ 'timestamp_format' ] , timestamp )
    header = header + timestamp
return header + data


signature:
def _read_header ( self , data ) :
    '''Read header from data'''

implementation:
# pylint : disable = W0212
version = self . _read_version ( data )
version_info = self . _get_version_info ( version )
header_data = data [ : version_info [ 'header_size' ] ]
header = version_info [ 'header' ]
header = header . _make ( unpack ( version_info [ 'header_format' ] , header_data ) )
header = dict ( header . _asdict ( ) )
flags = list ( "{0:0>8b}" . format ( header [ 'flags' ] ) )
flags = dict ( version_info [ 'flags' ] . _make ( flags ) . _asdict ( ) )
flags = dict ( ( i , bool ( int ( j ) ) ) for i , j in flags . iteritems ( ) )
header [ 'flags' ] = flags
timestamp = None
if flags [ 'timestamp' ] :
    ts_start = version_info [ 'header_size' ]
    ts_end = ts_start + version_info [ 'timestamp_size' ]
    timestamp_data = data [ ts_start : ts_end ]
    timestamp = unpack ( version_info [ 'timestamp_format' ] , timestamp_data ) [ 0 ]
header [ 'info' ] = { 'timestamp' : timestamp }
return header


signature:
def _remove_header ( self , data , options ) :
    '''Remove header from data'''

implementation:
version_info = self . _get_version_info ( options [ 'version' ] )
header_size = version_info [ 'header_size' ]
if options [ 'flags' ] [ 'timestamp' ] :
    header_size += version_info [ 'timestamp_size' ]
data = data [ header_size : ]
return data


signature:
def _read_version ( self , data ) :
    '''Read header version from data'''

implementation:
version = ord ( data [ 0 ] )
if version not in self . VERSIONS :
    raise Exception ( 'Version not defined: %d' % version )
return version


signature:
def _get_algorithm_info ( self , algorithm_info ) :
    '''Get algorithm info'''

implementation:
if algorithm_info [ 'algorithm' ] not in self . ALGORITHMS :
    raise Exception ( 'Algorithm not supported: %s' % algorithm_info [ 'algorithm' ] )
algorithm = self . ALGORITHMS [ algorithm_info [ 'algorithm' ] ]
algorithm_info . update ( algorithm )
return algorithm_info


signature:
def _generate_key ( pass_id , passphrases , salt , algorithm ) :
    '''Generate and return PBKDF2 key'''

implementation:
if pass_id not in passphrases :
    raise Exception ( 'Passphrase not defined for id: %d' % pass_id )
passphrase = passphrases [ pass_id ]
if len ( passphrase ) < 32 :
    raise Exception ( 'Passphrase less than 32 characters long' )
digestmod = EncryptedPickle . _get_hashlib ( algorithm [ 'pbkdf2_algorithm' ] )
encoder = PBKDF2 ( passphrase , salt , iterations = algorithm [ 'pbkdf2_iterations' ] , digestmodule = digestmod )
return encoder . read ( algorithm [ 'key_size' ] )


signature:
def _update_dict ( data , default_data , replace_data = False ) :
    '''Update algorithm definition type dictionaries'''

implementation:
if not data :
    data = default_data . copy ( )
    return data
if not isinstance ( data , dict ) :
    raise TypeError ( 'Value not dict type' )
if len ( data ) > 255 :
    raise ValueError ( 'More than 255 values defined' )
for i in data . keys ( ) :
    if not isinstance ( i , int ) :
        raise TypeError ( 'Index not int type' )
    if i < 0 or i > 255 :
        raise ValueError ( 'Index value out of range' )
if not replace_data :
    data . update ( default_data )
return data


signature:
def _get_hashlib ( digestmode ) :
    '''Generate HMAC hash'''

implementation:
if digestmode == 'sha1' :
    return SHA
if digestmode == 'sha256' :
    return SHA256
elif digestmode == 'sha384' :
    return SHA384
elif digestmode == 'sha512' :
    return SHA512
else :
    raise Exception ( 'digestmode not supported: %s' % digestmode )


signature:
def _hmac_generate ( data , algorithm , key ) :
    '''Generate HMAC hash'''

implementation:
digestmod = EncryptedPickle . _get_hashlib ( algorithm [ 'subtype' ] )
return HMAC . new ( key , data , digestmod ) . digest ( )


signature:
def _aes_encrypt ( data , algorithm , key ) :
    '''AES encrypt'''

implementation:
if algorithm [ 'subtype' ] == 'cbc' :
    mode = AES . MODE_CBC
else :
    raise Exception ( 'AES subtype not supported: %s' % algorithm [ 'subtype' ] )
iv_size = algorithm [ 'iv_size' ]
block_size = iv_size
include_iv = True
if 'iv' in algorithm and algorithm [ 'iv' ] :
    if len ( algorithm [ 'iv' ] ) != algorithm [ 'iv_size' ] :
        raise Exception ( 'Invalid IV size' )
    iv_value = algorithm [ 'iv' ]
    include_iv = False
else :
    iv_value = get_random_bytes ( iv_size )
numpad = block_size - ( len ( data ) % block_size )
data = data + numpad * chr ( numpad )
enc = AES . new ( key , mode , iv_value ) . encrypt ( data )
if include_iv :
    enc = iv_value + enc
return enc


signature:
def _aes_decrypt ( data , algorithm , key ) :
    '''AES decrypt'''

implementation:
if algorithm [ 'subtype' ] == 'cbc' :
    mode = AES . MODE_CBC
else :
    raise Exception ( 'AES subtype not supported: %s' % algorithm [ 'subtype' ] )
iv_size = algorithm [ 'iv_size' ]
if 'iv' in algorithm and algorithm [ 'iv' ] :
    if len ( algorithm [ 'iv' ] ) != algorithm [ 'iv_size' ] :
        raise Exception ( 'Invalid IV size' )
    iv_value = algorithm [ 'iv' ]
    enc = data
else :
    iv_value = data [ : iv_size ]
    enc = data [ iv_size : ]
dec = AES . new ( key , mode , iv_value ) . decrypt ( enc )
numpad = ord ( dec [ - 1 ] )
dec = dec [ 0 : - numpad ]
return dec


signature:
def _zlib_compress ( data , algorithm ) :
    '''GZIP compress'''

implementation:
if algorithm [ 'subtype' ] == 'deflate' :
    encoder = zlib . compressobj ( algorithm [ 'level' ] , zlib . DEFLATED , - 15 )
    compressed = encoder . compress ( data )
    compressed += encoder . flush ( )
    return compressed
else :
    raise Exception ( 'Compression subtype not supported: %s' % algorithm [ 'subtype' ] )


signature:
def getTableOfContents ( self ) :
    """This function populates the internal tableOfContents list with the contents
 of the zip file TOC . If the server does not support ranged requests , this will raise
 and exception . It will also throw an exception if the TOC cannot be found ."""

implementation:
self . directory_size = self . getDirectorySize ( )
if self . directory_size > 65536 :
    self . directory_size += 2
    self . requestContentDirectory ( )
# and find the offset from start of file where it can be found
directory_start = unpack ( "i" , self . raw_bytes [ self . directory_end + 16 : self . directory_end + 20 ] ) [ 0 ]
# find the data in the raw _ bytes
self . raw_bytes = self . raw_bytes
current_start = directory_start - self . start
filestart = 0
compressedsize = 0
tableOfContents = [ ]
try :
    while True : # get file name size ( n ) , extra len ( m ) and comm len ( k )
        zip_n = unpack ( "H" , self . raw_bytes [ current_start + 28 : current_start + 28 + 2 ] ) [ 0 ]
        zip_m = unpack ( "H" , self . raw_bytes [ current_start + 30 : current_start + 30 + 2 ] ) [ 0 ]
        zip_k = unpack ( "H" , self . raw_bytes [ current_start + 32 : current_start + 32 + 2 ] ) [ 0 ]
        filename = self . raw_bytes [ current_start + 46 : current_start + 46 + zip_n ]
        # check if this is the index file
        filestart = unpack ( "I" , self . raw_bytes [ current_start + 42 : current_start + 42 + 4 ] ) [ 0 ]
        compressedsize = unpack ( "I" , self . raw_bytes [ current_start + 20 : current_start + 20 + 4 ] ) [ 0 ]
        uncompressedsize = unpack ( "I" , self . raw_bytes [ current_start + 24 : current_start + 24 + 4 ] ) [ 0 ]
        tableItem = { 'filename' : filename , 'compressedsize' : compressedsize , 'uncompressedsize' : uncompressedsize , 'filestart' : filestart }
        tableOfContents . append ( tableItem )
        # not this file , move along
        current_start = current_start + 46 + zip_n + zip_m + zip_k
except :
    pass
self . tableOfContents = tableOfContents
return tableOfContents


signature:
def extractFile ( self , filename ) :
    """This function will extract a single file from the remote zip without downloading
 the entire zip file . The filename argument should match whatever is in the ' filename '
 key of the tableOfContents ."""

implementation:
files = [ x for x in self . tableOfContents if x [ 'filename' ] == filename ]
if len ( files ) == 0 :
    raise FileNotFoundException ( )
fileRecord = files [ 0 ]
# got here ? need to fetch the file size
metaheadroom = 1024
# should be enough
request = urllib2 . Request ( self . zipURI )
start = fileRecord [ 'filestart' ]
end = fileRecord [ 'filestart' ] + fileRecord [ 'compressedsize' ] + metaheadroom
request . headers [ 'Range' ] = "bytes=%s-%s" % ( start , end )
handle = urllib2 . urlopen ( request )
# make sure the response is ranged
return_range = handle . headers . get ( 'Content-Range' )
if return_range != "bytes %d-%d/%s" % ( start , end , self . filesize ) :
    raise Exception ( "Ranged requests are not supported for this URI" )
filedata = handle . read ( )
# find start of raw file data
zip_n = unpack ( "H" , filedata [ 26 : 28 ] ) [ 0 ]
zip_m = unpack ( "H" , filedata [ 28 : 30 ] ) [ 0 ]
# check compressed size
has_data_descriptor = bool ( unpack ( "H" , filedata [ 6 : 8 ] ) [ 0 ] & 8 )
comp_size = unpack ( "I" , filedata [ 18 : 22 ] ) [ 0 ]
if comp_size == 0 and has_data_descriptor : # assume compressed size in the Central Directory is correct
    comp_size = fileRecord [ 'compressedsize' ]
elif comp_size != fileRecord [ 'compressedsize' ] :
    raise Exception ( "Something went wrong. Directory and file header disagree of compressed file size" )
raw_zip_data = filedata [ 30 + zip_n + zip_m : 30 + zip_n + zip_m + comp_size ]
uncompressed_data = ""
# can ' t decompress if stored without compression
compression_method = unpack ( "H" , filedata [ 8 : 10 ] ) [ 0 ]
if compression_method == 0 :
    return raw_zip_data
dec = zlib . decompressobj ( - zlib . MAX_WBITS )
for chunk in raw_zip_data :
    rv = dec . decompress ( chunk )
    if rv :
        uncompressed_data = uncompressed_data + rv
return uncompressed_data


signature:
def make_postcard ( self , npix = 300 , shape = ( 1070 , 1132 ) , buffer_size = 15 ) :
    """Develop a " postcard " region around the target star .
 Other stars in this postcard will be used as possible reference stars .
 Args :
 npix : The size of the postcard region . The region will be a square with sides npix pixels
 ( default : ` ` 300 ` ` )
 shape : The size of each individual image . For Kepler / K2 FFIs this should never need to be
 changed from the default , but will be different for e . g . TESS FFIs ( default : ` ` ( 1070 , 1132 ) ` ` )
 buffer _ size : The number of pixels at the edge of the detector to avoid ( default : ` ` 15 ` ` )"""

implementation:
source = self . kic
client = kplr . API ( )
targ = client . target ( source )
channel = [ targ . params [ 'Channel_0' ] , targ . params [ 'Channel_1' ] , targ . params [ 'Channel_2' ] , targ . params [ 'Channel_3' ] ]
col = [ targ . params [ 'Column_0' ] , targ . params [ 'Column_1' ] , targ . params [ 'Column_2' ] , targ . params [ 'Column_3' ] ]
row = [ targ . params [ 'Row_0' ] , targ . params [ 'Row_1' ] , targ . params [ 'Row_2' ] , targ . params [ 'Row_3' ] ]
if None in row :
    raise ValueError ( 'Star not on detector all quarters!' )
if None in col :
    raise ValueError ( 'Star not on detector all quarters!' )
center = np . array ( [ npix / 2 , npix / 2 ] )
# If star close to edge , shift frame so that we have the full npix by npix
# In this case , postcard will not be centered on target star
if ( np . min ( col ) < npix / 2 ) :
    jump = npix / 2 - np . min ( col ) + buffer_size
    col += jump
    center [ 1 ] -= jump
if ( np . min ( row ) < npix / 2 ) :
    jump = npix / 2 - np . min ( row ) + buffer_size
    row += jump
    center [ 0 ] -= jump
if ( np . max ( row ) > shape [ 0 ] - npix / 2 ) :
    jump = shape [ 0 ] - npix / 2 - np . max ( row ) - buffer_size
    row += jump
    center [ 0 ] -= jump
if ( np . max ( col ) > shape [ 1 ] - npix / 2 ) :
    jump = shape [ 1 ] - npix / 2 - np . max ( col ) - buffer_size
    col += jump
    center [ 1 ] -= jump
fin_arr = np . zeros ( ( len ( self . times ) , npix , npix ) )
for icount , iname in enumerate ( self . obs_filenames ) :
    a = fits . open ( self . ffi_dir + iname )
    quarter = a [ 0 ] . header [ 'quarter' ]
    if int ( quarter ) == 0 :
        season = 3
    else :
        season = ( int ( quarter ) - 2 ) % 4
    # season _ arr [ icount ] = season
    img = a [ channel [ season ] ] . data
    img -= np . median ( img )
    ymin = int ( max ( [ int ( row [ season ] ) - npix / 2 , 0 ] ) )
    ymax = int ( min ( [ int ( row [ season ] ) + npix / 2 , img . shape [ 0 ] ] ) )
    xmin = int ( max ( [ int ( col [ season ] ) - npix / 2 , 0 ] ) )
    xmax = int ( min ( [ int ( col [ season ] ) + npix / 2 , img . shape [ 1 ] ] ) )
    pimg = img [ ymin : ymax , xmin : xmax ]
    fin_arr [ icount , : , : ] = pimg
self . postcard = fin_arr
self . integrated_postcard = np . sum ( self . postcard , axis = 0 )
self . center = center


signature:
def find_other_sources ( self , edge_lim = 0.015 , min_val = 5000 , ntargets = 250 , extend_region_size = 3 , remove_excess = 4 , plot_flag = False , plot_window = 15 ) :
    """Identify apertures for all sources on the postcard , both for the
 target and potential reference stars
 Args :
 edge _ lim : The initial limit for the creation of apertures . The aperture will be a region of
 contiguous pixels with flux values larger than the product of ` ` edge _ lim ` ` and the brightest
 pixel value for this star , as long as that product is larger than ` ` min _ val ` ` ( default : ` ` 0.015 ` ` )
 min _ val : Threshold for the minimum flux value in the ` ` integrated _ postcard ` ` for a pixel to be included
 in the default apertures ( default : ` ` 5000 ` ` )
 ntargets : The maximum number of potential reference stars to be included in the analysis ( default : ` ` 250 ` ` )
 extend _ region _ size : After the initial apertures are generated , they will be optionally extended an
 additional number of pixels following this flag . Safe practice for reasonable apertures is to
 leave ` ` min _ val ` ` at a value well above the noise and then extend apertures via this flag until
 they are of suitable size ( default : ` ` 3 ` ` )
 remove _ excess : Stars with apertures that touch will be combined into a single aperture .
 This is done by iterating through the starlist ; this flag represents the number of times the
 list will be iterated through to delete redundant apertures ( default : ` ` 4 ` ` )
 plot _ flag : If true , a series of diagnostic plots will appear while this function runs to observe
 apertures for the target star and other stars .
 ( default : ` ` False ` ` )
 plot _ window : If ` ` plot _ flag ` ` is ` ` True ` ` , the size of the region to be plotted around the target star
 to show the drawn aperture for visualization purposes only ( default : ` ` 15 ` ` )"""

implementation:
j , i = self . center
region = self . integrated_postcard + 0.0
if plot_flag == True :
    ff = plt . imshow ( self . integrated_postcard , interpolation = 'nearest' , cmap = 'gray' , vmax = np . percentile ( region , 99.6 ) )
    plt . colorbar ( ff )
    plt . show ( )
targets = np . zeros_like ( self . integrated_postcard )
sizeimg = np . shape ( targets ) [ 0 ]
jj = j + 0
ii = i + 0
edge = edge_lim
lim = max ( min_val , self . integrated_postcard [ int ( j ) , int ( i ) ] * edge )
maxpt = np . percentile ( self . integrated_postcard , 94 )
bin_img = ( region > lim )
lab_img , n_features = label ( bin_img )
key_targ = ( lab_img == ( lab_img [ int ( j ) , int ( i ) ] ) )
tot = np . sum ( key_targ )
targets [ key_targ ] = 1
region [ key_targ ] = 0.0
lim = np . zeros ( ntargets )
for peaks in range ( 1 , ntargets ) :
    k = np . argmax ( region )
    j , i = np . unravel_index ( k , region . shape )
    lim [ peaks ] = max ( maxpt , edge * region [ j , i ] )
    bin_img = ( region >= lim [ peaks ] )
    lab_img , n_features = label ( bin_img )
    key_targ = ( lab_img == ( lab_img [ j , i ] ) )
    targets [ key_targ ] = peaks + 1
    region [ key_targ ] = 0.0
lab_img , n_features = label ( targets )
for i in range ( 1 , ntargets + 1 ) :
    for j in range ( extend_region_size ) :
        border = mh . labeled . border ( targets , 0 , i )
        targets [ border * ( region < ( 10 ) * lim [ peaks ] ) ] = i
for i in range ( 2 , ntargets + 1 ) :
    for j in range ( 2 , ntargets + 1 ) :
        if i != j :
            border = mh . labeled . border ( targets , i , j )
            if np . sum ( border ) != 0 :
                targets [ targets == j ] = i
targets = mh . labeled . remove_bordering ( targets )
for k in range ( remove_excess ) :
    for i in range ( ntargets ) :
        if np . sum ( self . integrated_postcard [ targets == i ] ) < 0.01 :
            targets [ targets > i ] -= 1
self . targets = targets
if plot_flag == True :
    plt . imshow ( self . targets , interpolation = 'nearest' )
    plt . show ( )
    plt . imshow ( ( ( targets == 1 ) * self . integrated_postcard + ( targets == 1 ) * 100000 ) [ jj - plot_window : jj + plot_window , ii - plot_window : ii + plot_window ] , interpolation = 'nearest' , cmap = 'gray' , vmax = np . percentile ( self . integrated_postcard , 99.6 ) )
    plt . show ( )
    plt . imshow ( ( np . ceil ( targets / 100.0 ) * self . integrated_postcard + np . ceil ( targets / 500.0 ) * 3500000 ) , interpolation = 'nearest' , cmap = 'gray' , vmax = np . percentile ( self . integrated_postcard , 99.99 ) )
    plt . show ( )


signature:
def do_photometry ( self ) :
    """Does photometry and estimates uncertainties by calculating the scatter around a linear fit to the data
 in each orientation . This function is called by other functions and generally the user will not need
 to interact with it directly ."""

implementation:
std_f = np . zeros ( 4 )
data_save = np . zeros_like ( self . postcard )
self . obs_flux = np . zeros_like ( self . reference_flux )
for i in range ( 4 ) :
    g = np . where ( self . qs == i ) [ 0 ]
    wh = np . where ( self . times [ g ] > 54947 )
    data_save [ g ] = np . roll ( self . postcard [ g ] , int ( self . roll_best [ i , 0 ] ) , axis = 1 )
    data_save [ g ] = np . roll ( data_save [ g ] , int ( self . roll_best [ i , 1 ] ) , axis = 2 )
    self . target_flux_pixels = data_save [ : , self . targets == 1 ]
    self . target_flux = np . sum ( self . target_flux_pixels , axis = 1 )
    self . obs_flux [ g ] = self . target_flux [ g ] / self . reference_flux [ g ]
    self . obs_flux [ g ] /= np . median ( self . obs_flux [ g [ wh ] ] )
    fitline = np . polyfit ( self . times [ g ] [ wh ] , self . obs_flux [ g ] [ wh ] , 1 )
    std_f [ i ] = np . max ( [ np . std ( self . obs_flux [ g ] [ wh ] / ( fitline [ 0 ] * self . times [ g ] [ wh ] + fitline [ 1 ] ) ) , 0.001 ] )
self . flux_uncert = std_f


signature:
def generate_panel ( self , img ) :
    """Creates the figure shown in ` ` adjust _ aperture ` ` for visualization purposes . Called by other functions
 and generally not called by the user directly .
 Args :
 img : The data frame to be passed through to be plotted . A cutout of the ` ` integrated _ postcard ` `"""

implementation:
plt . figure ( figsize = ( 14 , 6 ) )
ax = plt . gca ( )
fig = plt . gcf ( )
plt . subplot ( 122 )
data_save = np . zeros_like ( self . postcard )
self . roll_best = np . zeros ( ( 4 , 2 ) )
for i in range ( 4 ) :
    g = np . where ( self . qs == i ) [ 0 ]
    wh = np . where ( self . times [ g ] > 54947 )
    self . roll_best [ i ] = self . do_rolltest ( g , wh )
self . do_photometry ( )
for i in range ( 4 ) :
    g = np . where ( self . qs == i ) [ 0 ]
    plt . errorbar ( self . times [ g ] , self . obs_flux [ g ] , yerr = self . flux_uncert [ i ] , fmt = fmt [ i ] )
plt . xlabel ( 'Time' , fontsize = 20 )
plt . ylabel ( 'Relative Flux' , fontsize = 20 )
plt . subplot ( 121 )
implot = plt . imshow ( img , interpolation = 'nearest' , cmap = 'gray' , vmin = 98000 * 52 , vmax = 104000 * 52 )
cid = fig . canvas . mpl_connect ( 'button_press_event' , self . onclick )
plt . show ( block = True )


signature:
def adjust_aperture ( self , image_region = 15 , ignore_bright = 0 ) :
    """Develop a panel showing the current aperture and the light curve as judged from that aperture .
 Clicking on individual pixels on the aperture will toggle those pixels on or off into the
 aperture ( which will be updated after closing the plot ) .
 Clicking on the 0th row or column will turn off all pixels in that column or row , respectively .
 Will iterate continuously until the figure is closed without updating any pixels .
 Args :
 image _ region : The size of the region around the target star to be plotted . Images will be a square
 with side length ` ` image _ region ` ` ( default : ` ` 15 ` ` )
 ignore _ bright : The number of brightest stars to be ignored in the determination of the flux from
 reference stars . If there is reason to believe ( for example ) that saturated stars may behave
 differently than the target star , they can be avoided with this flag ( default : ` ` 0 ` ` )"""

implementation:
self . ignore_bright = ignore_bright
self . calc_fluxes ( )
self . coordsx = [ ]
self . coordsy = [ ]
jj , ii = self . center
jj , ii = int ( jj ) , int ( ii )
# Indices must be integer
plt . ion ( )
img = np . sum ( ( ( self . targets == 1 ) * self . postcard + ( self . targets == 1 ) * 100000 ) [ : , jj - image_region : jj + image_region , ii - image_region : ii + image_region ] , axis = 0 )
self . generate_panel ( img )
while len ( self . coordsx ) != 0 :
    for i in range ( len ( self . coordsx ) ) :
        if self . targets [ self . coordsy [ i ] + jj - image_region , self . coordsx [ i ] + ii - image_region ] != 1 :
            self . targets [ self . coordsy [ i ] + jj - image_region , self . coordsx [ i ] + ii - image_region ] = 1
        elif self . targets [ self . coordsy [ i ] + jj - image_region , self . coordsx [ i ] + ii - image_region ] == 1 :
            self . targets [ self . coordsy [ i ] + jj - image_region , self . coordsx [ i ] + ii - image_region ] = 0
        if self . coordsy [ i ] == 0 :
            thiscol = np . where ( self . targets [ : , self . coordsx [ i ] + ii - image_region ] == 1 )
            self . targets [ thiscol , self . coordsx [ i ] + ii - image_region ] = 0
        if self . coordsx [ i ] == 0 :
            thiscol = np . where ( self . targets [ self . coordsy [ i ] + jj - image_region , : ] == 1 )
            self . targets [ self . coordsy [ i ] + jj - image_region , thiscol ] = 0
    self . coordsx = [ ]
    self . coordsy = [ ]
    img = np . sum ( ( ( self . targets == 1 ) * self . postcard + ( self . targets == 1 ) * 100000 ) [ : , jj - image_region : jj + image_region , ii - image_region : ii + image_region ] , axis = 0 )
    self . generate_panel ( img )


signature:
def data_for_target ( self , do_roll = True , ignore_bright = 0 ) :
    """Determine the normalized photometry , accounting for effects shared by reference stars . Does not provide
 the opportunity to adjust the aperture
 Args :
 image _ region : If ` ` True ` ` allow the aperture to be shifted up to one pixel in both the x and y
 directions to account for differential velocity aberration ( default : ` ` True ` ` )
 ignore _ bright : The number of brightest stars to be ignored in the determination of the flux from
 reference stars . If there is reason to believe ( for example ) that saturated stars may behave
 differently than the target star , they can be avoided with this flag ( default : ` ` 0 ` ` )"""

implementation:
self . ignore_bright = ignore_bright
self . calc_fluxes ( )
self . roll_best = np . zeros ( ( 4 , 2 ) )
if do_roll == True :
    for i in range ( 4 ) :
        g = np . where ( self . qs == i ) [ 0 ]
        wh = np . where ( self . times [ g ] > 54947 )
        self . roll_best [ i ] = self . do_rolltest ( g , wh )
self . do_photometry ( )


signature:
def calc_fluxes ( self , min_flux = 5000 , outlier_iterations = 5 , max_outlier_obs = 4 , outlier_limit = 1.7 ) :
    """Determine the suitable reference stars , and then the total flux in those stars and
 in the target star in each epoch
 Args :
 min _ flux : The size of the region around the target star to be plotted . Images will be a square
 with side length ` ` image _ region ` ` ( default : ` ` 5000 ` ` )
 outlier _ iterations : The number of iterations to remove outliers from the reference star sample
 ( stars at epochs with more than ` ` max _ outlier _ obs ` ` observations more than ` ` outlier _ limit ` ` standard
 deviations from the median value for all stars after normalization ) ( default : ` ` 5 ` ` )
 max _ outlier _ obs : The maximum number of epochs at which a star is allowed to be more than ` ` outlier _ limit ` `
 standard deviations from the median value for all stars before it is removed as a suitable
 reference star ( default : ` ` 4 ` ` )
 outlier _ limit : The level of deviation ( measured in standard deviations ) which a target is allowed
 to be discrepant from the median . If it is this discrepant at more than ` ` max _ outlier _ obs ` `
 epochs , it is removed from consideration ( default : ` ` 1.7 ` ` )"""

implementation:
jj , ii = self . center
numer = np . zeros ( len ( self . times ) )
denom = np . zeros ( len ( self . times ) )
factr = np . zeros ( len ( self . times ) )
numer_pix = self . postcard [ : , self . targets == 1 ]
numer = np . sum ( numer_pix , axis = 1 )
tar_vals = np . zeros ( ( len ( self . times ) , int ( np . max ( self . targets ) + 1 - 2 - self . ignore_bright ) ) )
for i in range ( 2 + self . ignore_bright , int ( np . max ( self . targets ) + 1 ) ) :
    tval = np . sum ( self . postcard [ : , self . targets == i ] , axis = 1 )
    # denom + = tval / np . median ( tval )
    tar_vals [ : , i - 2 - self . ignore_bright ] = tval
# / np . median ( tval )
for i in range ( len ( self . obs_filenames ) ) :
    if np . max ( tar_vals [ i ] ) < min_flux :
        tar_vals [ self . qs == self . qs [ i ] ] = 0.0
all_tar = np . zeros ( ( len ( self . times ) , int ( np . max ( self . targets ) - self . ignore_bright ) ) )
all_tar [ : , 0 ] = numer
all_tar [ : , 1 : ] = tar_vals
self . photometry_array = all_tar
for i in range ( len ( tar_vals [ 0 ] ) ) :
    for j in range ( 4 ) :
        g = np . where ( self . qs == j ) [ 0 ]
        tar_vals [ g , i ] /= ( np . median ( tar_vals [ g , i ] ) + 1e-15 )
tar_vals_old = tar_vals + 0.0
for i in range ( outlier_iterations ) :
    nonzeros = np . where ( tar_vals [ 0 , : ] != 0 ) [ 0 ]
    med = np . median ( tar_vals [ : , nonzeros ] , axis = 1 )
    std = np . std ( tar_vals [ : , nonzeros ] , axis = 1 )
    if np . sum ( tar_vals ) != 0.0 :
        tar_vals_old = tar_vals + 0.0
    for k in range ( len ( tar_vals [ 0 ] ) ) :
        h = np . where ( ( np . abs ( med - tar_vals [ : , k ] ) / std ) > outlier_limit ) [ 0 ]
        if len ( h ) >= max_outlier_obs :
            tar_vals [ : , k ] = 0
if np . sum ( tar_vals ) == 0.0 :
    tar_vals = tar_vals_old + 0.0
denom = np . sum ( tar_vals , axis = 1 )
self . target_flux_pixels = numer_pix
self . reference_flux = denom


signature:
def calc_centroids ( self ) :
    """Identify the centroid positions for the target star at all epochs . Useful for verifying that there is
 no correlation between flux and position , as might be expected for high proper motion stars ."""

implementation:
self . cm = np . zeros ( ( len ( self . postcard ) , 2 ) )
for i in range ( len ( self . postcard ) ) :
    target = self . postcard [ i ]
    target [ self . targets != 1 ] = 0.0
    self . cm [ i ] = center_of_mass ( target )


signature:
def define_spotsignal ( self ) :
    """Identify the " expected " flux value at the time of each observation based on the
 Kepler long - cadence data , to ensure variations observed are not the effects of a single
 large starspot . Only works if the target star was targeted for long or short cadence
 observations during the primary mission ."""

implementation:
client = kplr . API ( )
star = client . star ( self . kic )
lcs = star . get_light_curves ( short_cadence = False )
time , flux , ferr , qual = [ ] , [ ] , [ ] , [ ]
for lc in lcs :
    with lc . open ( ) as f :
        hdu_data = f [ 1 ] . data
        time . append ( hdu_data [ "time" ] )
        flux . append ( hdu_data [ "pdcsap_flux" ] )
        ferr . append ( hdu_data [ "pdcsap_flux_err" ] )
        qual . append ( hdu_data [ "sap_quality" ] )
    tout = np . array ( [ ] )
    fout = np . array ( [ ] )
    eout = np . array ( [ ] )
    for i in range ( len ( flux ) ) :
        t = time [ i ] [ qual [ i ] == 0 ]
        f = flux [ i ] [ qual [ i ] == 0 ]
        e = ferr [ i ] [ qual [ i ] == 0 ]
        t = t [ np . isfinite ( f ) ]
        e = e [ np . isfinite ( f ) ]
        f = f [ np . isfinite ( f ) ]
        e /= np . median ( f )
        f /= np . median ( f )
        tout = np . append ( tout , t [ 50 : ] + 54833 )
        fout = np . append ( fout , f [ 50 : ] )
        eout = np . append ( eout , e [ 50 : ] )
    self . spot_signal = np . zeros ( 52 )
    for i in range ( len ( self . times ) ) :
        if self . times [ i ] < 55000 :
            self . spot_signal [ i ] = 1.0
        else :
            self . spot_signal [ i ] = fout [ np . abs ( self . times [ i ] - tout ) == np . min ( np . abs ( self . times [ i ] - tout ) ) ]


signature:
def model_uncert ( self ) :
    """Estimate the photometric uncertainties on each data point following Equation A . 2 of The Paper .
 Based on the kepcal package of Dan Foreman - Mackey ."""

implementation:
Y = self . photometry_array . T
Y /= np . median ( Y , axis = 1 ) [ : , None ]
C = np . median ( Y , axis = 0 )
nstars , nobs = np . shape ( Y )
Z = np . empty ( ( nstars , 4 ) )
qs = self . qs . astype ( int )
for s in range ( 4 ) :
    Z [ : , s ] = np . median ( ( Y / C ) [ : , qs == s ] , axis = 1 )
resid2 = ( Y - Z [ : , qs ] * C ) ** 2
z = Z [ : , qs ]
trend = z * C [ None , : ]
lnS = np . log ( np . nanmedian ( resid2 , axis = 0 ) )
jitter = np . log ( 0.1 * np . nanmedian ( np . abs ( np . diff ( Y , axis = 1 ) ) ) )
cal_ferr = np . sqrt ( np . exp ( 2 * ( jitter / trend ) ) + z ** 2 * np . exp ( lnS ) [ None , : ] )
self . modeled_uncert = cal_ferr
self . target_uncert = cal_ferr [ 0 ]


signature:
def _print ( self , line = '' ) :
    """Append line to internal list .
 Uses self . tabs to format indents .
 Keyword arguments :
 line - - line to append"""

implementation: self . lines . append ( '{}{}' . format ( '\t' * self . tabs , line ) )


signature:
def _dump_enum ( self , e , top = '' ) :
    """Dump single enum type .
 Keyword arguments :
 top - - top namespace"""

implementation:
self . _print ( )
self . _print ( 'enum {} {{' . format ( e . name ) )
self . defines . append ( '{}.{}' . format ( top , e . name ) )
self . tabs += 1
for v in e . value :
    self . _print ( '{} = {};' . format ( v . name , v . number ) )
self . tabs -= 1
self . _print ( '}' )


signature:
def _dump_field ( self , fd ) :
    """Dump single field ."""

implementation:
v = { }
v [ 'label' ] = Pbd . LABELS [ fd . label ]
v [ 'type' ] = fd . type_name if len ( fd . type_name ) > 0 else Pbd . TYPES [ fd . type ]
v [ 'name' ] = fd . name
v [ 'number' ] = fd . number
v [ 'default' ] = '[default = {}]' . format ( fd . default_value ) if len ( fd . default_value ) > 0 else ''
f = '{label} {type} {name} = {number} {default};' . format ( ** v )
f = ' ' . join ( f . split ( ) )
self . _print ( f )
if len ( fd . type_name ) > 0 :
    self . uses . append ( fd . type_name )


signature:
def _dump_message ( self , m , top = '' ) :
    """Dump single message type .
 Keyword arguments :
 top - - top namespace"""

implementation:
self . _print ( )
self . _print ( 'message {} {{' . format ( m . name ) )
self . defines . append ( '{}.{}' . format ( top , m . name ) )
self . tabs += 1
for f in m . field :
    self . _dump_field ( f )
for e in m . enum_type :
    self . _dump_enum ( e , top = '{}.{}' . format ( top , m . name ) )
for n in m . nested_type :
    self . _dump_message ( n , top = '{}.{}' . format ( top , m . name ) )
self . tabs -= 1
self . _print ( '}' )


signature:
def _walk ( self , fd ) :
    """Walk and dump ( disasm ) descriptor ."""

implementation:
top = '.{}' . format ( fd . package ) if len ( fd . package ) > 0 else ''
for e in fd . enum_type :
    self . _dump_enum ( e , top )
for m in fd . message_type :
    self . _dump_message ( m , top )


signature:
def disassemble ( self ) :
    """Disassemble serialized protocol buffers file ."""

implementation:
ser_pb = open ( self . input_file , 'rb' ) . read ( )
# Read serialized pb file
fd = FileDescriptorProto ( )
fd . ParseFromString ( ser_pb )
self . name = fd . name
self . _print ( '// Reversed by pbd (https://github.com/rsc-dev/pbd)' )
self . _print ( 'syntax = "proto2";' )
self . _print ( '' )
if len ( fd . package ) > 0 :
    self . _print ( 'package {};' . format ( fd . package ) )
    self . package = fd . package
else :
    self . _print ( '// Package not defined' )
self . _walk ( fd )


signature:
def dump ( self , out_dir = '.' ) :
    """Dump proto file to given directory .
 Keyword arguments :
 out _ dir - - dump directory . Default = ' . '"""

implementation:
uri = out_dir + os . sep + self . name
with open ( uri , 'w' ) as fh :
    fh . write ( '\n' . join ( self . lines ) )


signature:
def find_imports ( self , pbds ) :
    """Find all missing imports in list of Pbd instances ."""

implementation:
# List of types used , but not defined
imports = list ( set ( self . uses ) . difference ( set ( self . defines ) ) )
# Clumpsy , but enought for now
for imp in imports :
    for p in pbds :
        if imp in p . defines :
            self . imports . append ( p . name )
            break
self . imports = list ( set ( self . imports ) )
for import_file in self . imports :
    self . lines . insert ( 2 , 'import "{}";' . format ( import_file ) )


signature:
def fasta_file_to_dict ( fasta_file , id = True , header = False , seq = False ) :
    """Returns a dict from a fasta file and the number of sequences as the second return value .
 fasta _ file can be a string path or a file object .
 The key of fasta _ dict can be set using the keyword arguments and
 results in a combination of id , header , sequence , in that order . joined with ' | | ' . ( default : id )
 Duplicate keys are checked and a warning is logged if found .
 The value of fasta _ dict is a python dict with 3 keys : header , id and seq
 Changelog :
 2014/11/17:
 * Added support for url escaped id"""

implementation:
fasta_file_f = fasta_file
if isinstance ( fasta_file , str ) :
    fasta_file_f = open ( fasta_file , 'rb' )
fasta_dict = OrderedDict ( )
keys = [ 'id' , 'header' , 'seq' ]
flags = dict ( [ ( 'id' , id ) , ( 'header' , header ) , ( 'seq' , seq ) ] )
entry = dict ( [ ( 'id' , '' ) , ( 'header' , '' ) , ( 'seq' , '' ) ] )
count = 0
line_num = 0
for line in fasta_file_f :
    line = line . strip ( )
    if line and line [ 0 ] == '>' :
        count += 1
        key = '||' . join ( [ entry [ i ] for i in keys if flags [ i ] ] )
        if key : # key ! = ' '
            if key in fasta_dict : # check for duplicate key
                logger . warning ( '%s : Line %d : Duplicate %s [%s] : ID = [%s].' , fasta_file_f . name , line_num , '||' . join ( [ i for i in keys if flags [ i ] ] ) , key [ : 25 ] + ( key [ 25 : ] and '..' ) , entry [ 'id' ] )
            entry [ 'seq' ] = '' . join ( entry [ 'seq' ] )
            fasta_dict [ key ] = entry
            # check for url escaped id
            if id :
                unescaped_id = unquote ( entry [ 'id' ] )
                if id != unescaped_id :
                    key = '||' . join ( [ unescaped_id ] + [ entry [ i ] for i in keys if i != 'id' and flags [ i ] ] )
                    entry [ 'unescaped_id' ] = unescaped_id
                    fasta_dict [ key ] = entry
            entry = dict ( )
        entry [ 'header' ] = line
        entry [ 'id' ] = line . split ( ) [ 0 ] [ 1 : ]
        entry [ 'seq' ] = [ ]
    else :
        entry [ 'seq' ] . append ( line . upper ( ) )
    line_num += 1
if isinstance ( fasta_file , str ) :
    fasta_file_f . close ( )
key = '||' . join ( [ entry [ i ] for i in keys if flags [ i ] ] )
if key : # key ! = ' '
    if key in fasta_dict :
        logger . warning ( '%s : Line %d : Duplicate %s [%s] : ID = [%s].' , fasta_file_f . name , line_num , '||' . join ( [ i for i in keys if flags [ i ] ] ) , key [ : 25 ] + ( key [ 25 : ] and '..' ) , entry [ 'id' ] )
    entry [ 'seq' ] = '' . join ( entry [ 'seq' ] )
    fasta_dict [ key ] = entry
    # check for url escaped id
    if id :
        unescaped_id = unquote ( entry [ 'id' ] )
        if id != unescaped_id :
            key = '||' . join ( [ unescaped_id ] + [ entry [ i ] for i in keys if i != 'id' and flags [ i ] ] )
            entry [ 'unescaped_id' ] = unescaped_id
            fasta_dict [ key ] = entry
return fasta_dict , count


signature:
def fasta_dict_to_file ( fasta_dict , fasta_file , line_char_limit = None ) :
    """Write fasta _ dict to fasta _ file
 : param fasta _ dict : returned by fasta _ file _ to _ dict
 : param fasta _ file : output file can be a string path or a file object
 : param line _ char _ limit : None = no limit ( default )
 : return : None"""

implementation:
fasta_fp = fasta_file
if isinstance ( fasta_file , str ) :
    fasta_fp = open ( fasta_file , 'wb' )
for key in fasta_dict :
    seq = fasta_dict [ key ] [ 'seq' ]
    if line_char_limit :
        seq = '\n' . join ( [ seq [ i : i + line_char_limit ] for i in range ( 0 , len ( seq ) , line_char_limit ) ] )
    fasta_fp . write ( u'{0:s}\n{1:s}\n' . format ( fasta_dict [ key ] [ 'header' ] , seq ) )


signature:
def add_line_error ( self , line_data , error_info , log_level = logging . ERROR ) :
    """Helper function to record and log an error message
 : param line _ data : dict
 : param error _ info : dict
 : param logger :
 : param log _ level : int
 : return :"""

implementation:
if not error_info :
    return
try :
    line_data [ 'line_errors' ] . append ( error_info )
except KeyError :
    line_data [ 'line_errors' ] = [ error_info ]
except TypeError : # no line _ data
    pass
try :
    self . logger . log ( log_level , Gff3 . error_format . format ( current_line_num = line_data [ 'line_index' ] + 1 , error_type = error_info [ 'error_type' ] , message = error_info [ 'message' ] , line = line_data [ 'line_raw' ] . rstrip ( ) ) )
except AttributeError : # no logger
    pass


signature:
def check_parent_boundary ( self ) :
    """checks whether child features are within the coordinate boundaries of parent features
 : return :"""

implementation:
for line in self . lines :
    for parent_feature in line [ 'parents' ] :
        ok = False
        for parent_line in parent_feature :
            if parent_line [ 'start' ] <= line [ 'start' ] and line [ 'end' ] <= parent_line [ 'end' ] :
                ok = True
                break
        if not ok :
            self . add_line_error ( line , { 'message' : 'This feature is not contained within the feature boundaries of parent: {0:s}: {1:s}' . format ( parent_feature [ 0 ] [ 'attributes' ] [ 'ID' ] , ',' . join ( [ '({0:s}, {1:d}, {2:d})' . format ( line [ 'seqid' ] , line [ 'start' ] , line [ 'end' ] ) for line in parent_feature ] ) ) , 'error_type' : 'BOUNDS' , 'location' : 'parent_boundary' } )


signature:
def check_phase ( self ) :
    """1 . get a list of CDS with the same parent
 2 . sort according to strand
 3 . calculate and validate phase"""

implementation:
plus_minus = set ( [ '+' , '-' ] )
for k , g in groupby ( sorted ( [ line for line in self . lines if line [ 'line_type' ] == 'feature' and line [ 'type' ] == 'CDS' and 'Parent' in line [ 'attributes' ] ] , key = lambda x : x [ 'attributes' ] [ 'Parent' ] ) , key = lambda x : x [ 'attributes' ] [ 'Parent' ] ) :
    cds_list = list ( g )
    strand_set = list ( set ( [ line [ 'strand' ] for line in cds_list ] ) )
    if len ( strand_set ) != 1 :
        for line in cds_list :
            self . add_line_error ( line , { 'message' : 'Inconsistent CDS strand with parent: {0:s}' . format ( k ) , 'error_type' : 'STRAND' } )
        continue
    if len ( cds_list ) == 1 :
        if cds_list [ 0 ] [ 'phase' ] != 0 :
            self . add_line_error ( cds_list [ 0 ] , { 'message' : 'Wrong phase {0:d}, should be {1:d}' . format ( cds_list [ 0 ] [ 'phase' ] , 0 ) , 'error_type' : 'PHASE' } )
        continue
    strand = strand_set [ 0 ]
    if strand not in plus_minus : # don ' t process unknown strands
        continue
    if strand == '-' : # sort end descending
        sorted_cds_list = sorted ( cds_list , key = lambda x : x [ 'end' ] , reverse = True )
    else :
        sorted_cds_list = sorted ( cds_list , key = lambda x : x [ 'start' ] )
    phase = 0
    for line in sorted_cds_list :
        if line [ 'phase' ] != phase :
            self . add_line_error ( line , { 'message' : 'Wrong phase {0:d}, should be {1:d}' . format ( line [ 'phase' ] , phase ) , 'error_type' : 'PHASE' } )
        phase = ( 3 - ( ( line [ 'end' ] - line [ 'start' ] + 1 - phase ) % 3 ) ) % 3