B
    dn                 @   s  d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlZddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlZdZdej ZejZdd Zi Ze	  Z!i Z"ej#ej$fdfddZ%d9ddZ&d:ddZ'd;ddZ(d<ddZ)d=ddZ*dd Z+dd  Z,d!d" Z-d#d$ Z.d%d& Z/e0d'ej1Z2e0d(Z3d)d* Z4d+d, Z5d>d-d.Z6G d/d0 d0ej7Z8G d1d2 d2e8Z9G d3d4 d4e8Z:d?d5d6Z;e9j<e9e:j<e:iZ=d7d8 Z>dS )@a  
This module provides an implementation of the Table element that uses a
database engine for storage.  On top of that it then re-implements a number
of the tables from the lsctables module to provide versions of their
methods that work against the SQL database.
    N)AttributesImpl)segments)git_version   )ilwd)ligolw)table)	lsctables)typesz"Kipp Cannon <kipp.cannon@ligo.org>z	git id %sc             C   s,   dt | krdS dt | kr dS t| dS )a,  
	A totally broken attempt to determine what type of database a
	connection object is attached to.  Don't use this.

	The input is a DB API 2.0 compliant connection object, the return
	value is one of the strings "sqlite3" or "mysql".  Raises TypeError
	when the database type cannot be determined.
	sqlitemysqlN)repr	TypeError)
connection r   a/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/glue/ligolw/dbtables.pyconnection_db_typeI   s
    	r   c                sV   t | t t }  fdd}x4| D ],}t|t|< t| tjkr"t|| q"W dS )a3  
	Installs a signal handler to erase temporary scratch files when a
	signal is received.  This can be used to help ensure scratch files
	are erased when jobs are evicted by Condor.  signums is a squence
	of the signals to trap, the default value is a list of the signals
	used by Condor to kill and/or evict jobs.

	The logic is as follows.  If the current signal handler is
	signal.SIG_IGN, i.e. the signal is being ignored, then the signal
	handler is not modified since the reception of that signal would
	not normally cause a scratch file to be leaked.  Otherwise a signal
	handler is installed that erases the scratch files.  If the
	original signal handler was a Python callable, then after the
	scratch files are erased the original signal handler will be
	invoked.  If program control returns from that handler, i.e.  that
	handler does not cause the interpreter to exit, then sys.exit() is
	invoked and retval is returned to the shell as the exit code.

	Note:  by invoking sys.exit(), the signal handler causes the Python
	interpreter to do a normal shutdown.  That means it invokes
	atexit() handlers, and does other garbage collection tasks that it
	normally would not do when killed by a signal.

	Note:  this function will not replace a signal handler more than
	once, that is if it has already been used to set a handler
	on a signal then it will be a no-op when called again for that
	signal until uninstall_signal_trap() is used to remove the handler
	from that signal.

	Note:  this function is called by get_connection_filename()
	whenever it creates a scratch file.
	c          	      s@   t  t  W d Q R X tt|  r2t|  | |S t  d S )N)temporary_files_locktemporary_filesclearcallableorigactionssysexit)signumframe)retvalr   r    temporary_file_cleanup_on_signal   s
    z=install_signal_trap.<locals>.temporary_file_cleanup_on_signalN)setr   signal	getsignalSIG_IGN)signumsr   r   r   r   )r   r   install_signal_trapn   s    #

r#   c             C   s8   | dkrt t } x| D ]}t|t| qW dS )a  
	Undo the effects of install_signal_trap().  Restores the original
	signal handlers.  If signums is a sequence of signal numbers only
	the signal handlers for those signals will be restored (KeyError
	will be raised if one of them is not one that install_signal_trap()
	installed a handler for, in which case some undefined number of
	handlers will have been restored).  If signums is None (the
	default) then all signals that have been modified by previous calls
	to install_signal_trap() are restored.

	Note:  this function is called by put_connection_filename() and
	discard_connection_filename() whenever they remove a scratch file
	and there are then no more scrach files in use.
	N)listr   keysr   pop)r"   r   r   r   r   uninstall_signal_trap   s    
r'   Fc                s  ddd}ddd}d fdd	}t  t j}|d	k	rj||d
t j d d
dd	 |d|r|r| |d nd}xy| |d W n tk
r` }	 zdd	l}
dd	l}|	j|
j	|
j
fkr҂ |dk r| rtjd||
j|	j f  |d |d7 }w|r6tjd||
j|	j  f  t t= W d	Q R X  W d	d	}	~	X Y nX P qW nBt  tkrtd  W d	Q R X  |r|r||d ~~~S )z
	Utility code for moving database files to a (presumably local)
	working location for improved performance and reduced fileserver
	load.
	.sqliteFc          	   S   s   t N t  tj|| dkr| ntdd}|jfdd}||_|j}|t|< W d Q R X |rlt	j
d|  td}t| t|d| @  |S )N_CONDOR_SCRATCH_DIR)suffixdirc             S   s*   y|d|   W n   Y nX ||  d S )Nz
%s-journalr   )selfZorig_unlinkr   r   r   
new_unlink   s
    z:get_connection_filename.<locals>.mktmp.<locals>.new_unlinkzusing '%s' as workspace
i  i  )r   r#   tempfileNamedTemporaryFileosgetenvunlinknamer   r   stderrwriteumaskchmod)pathr*   verboseZtemporary_filer-   filenameZumskr   r   r   mktmp   s     

z&get_connection_filename.<locals>.mktmpc          
   S   s   |rt jd|   yt| tjtjB }W n> tk
rj } z |rZt jd| t|f  d S d }~X Y nX t	| |rt jd d S )Nz'%s' exists, truncating ... zcannot truncate '%s': %s
zdone.
)
r   r4   r5   r0   openO_WRONLYO_TRUNC	Exceptionstrclose)r:   r9   fder   r   r   truncate   s    
z)get_connection_filename.<locals>.truncatec          
      s   |rt jd| |f  t| | |r4t jd yt| | W n@ tk
r } z"|rtt jd t|f  W d d }~X Y nX d S )Nzcopying '%s' to '%s' ... zdone.
zHwarning: ignoring failure to copy permission bits from '%s' to '%s': %s
)r   r4   r5   shutilcopy2copystatr?   r@   )srcnamedstnamer9   rC   )r:   targetr   r   cpy   s    z$get_connection_filename.<locals>.cpyN.r   )r*   r9   )r9   r      z7warning: attempt %d: %s, sleeping and trying again ...

   z9warning: attempt %d: %s: working with original file '%s'
zXfile '%s' appears to be in use already as a temporary database file and is to be deleted)r(   F)F)F)r0   accessF_OKjoinr8   splitIOErrorerrnotimeEPERMZENOSPCr   r4   r5   	errorcodesleepr   r   
ValueError)r:   Ztmp_pathZreplace_filer9   r;   rD   rK   Zdatabase_existsirC   rU   rV   r   )r:   rJ   r   get_connection_filename   sP    


.


r\   c             C   sX   |dkrt d}|r&tjd|  |  }|d|  |  |rTtjd dS )z6
	Sets the temp_store_directory parameter in sqlite.
	r)   z+setting the temp_store_directory to %s ... z"PRAGMA temp_store_directory = '%s'zdone
N)r0   r1   r   r4   r5   cursorexecuterA   )r   Ztemp_store_directoryr9   r]   r   r   r   set_temp_store_directory7  s    
r_   c          	      s  || krg   fdd}i }x.t jt jfD ]}t |||< t  || q,W |rftjd|| f  t||  |rtjd yt	|d
  W n   Y nX t t|= W dQ R X x"t|D ]\}}t  || qW x rtt  d qW t tst  W dQ R X dS )a  
	This function reverses the effect of a previous call to
	get_connection_filename(), restoring the working copy to its
	original location if the two are different.  This function should
	always be called after calling get_connection_filename() when the
	file is no longer in use.

	During the move operation, this function traps the signals used by
	Condor to evict jobs.  This reduces the risk of corrupting a
	document by the job terminating part-way through the restoration of
	the file to its original location.  When the move operation is
	concluded, the original signal handlers are restored and if any
	signals were trapped they are resent to the current process in
	order.  Typically this will result in the signal handlers installed
	by the install_signal_trap() function being invoked, meaning any
	other scratch files that might be in use get deleted and the
	current process is terminated.
	c                s     |  d S )N)append)r   r   )deferred_signalsr   r   
newsigterm\  s    z+put_connection_filename.<locals>.newsigtermzmoving '%s' to '%s' ... zdone.
wNr   )r   SIGTERMSIGTSTPr    r   r4   r5   rE   mover<   rA   r   r   six	iteritemsr0   killgetpidr&   r'   )r:   working_filenamer9   rb   ZoldhandlerssigZ
oldhandlerr   )ra   r   put_connection_filenameF  s2    
	rm   c          	   C   sT   || krdS t : |r&tjd|  t|= |r<tjd tsFt  W dQ R X dS )a  
	Like put_connection_filename(), but the working copy is simply
	deleted instead of being copied back to its original location.
	This is a useful performance boost if it is known that no
	modifications were made to the file, for example if queries were
	performed but no updates.

	Note that the file is not deleted if the working copy and original
	file are the same, so it is always safe to call this function after
	a call to get_connection_filename() even if a separate working copy
	is not created.
	Nzremoving '%s' ... zdone.)r   r   r4   r5   r   r'   )r:   rk   r9   r   r   r   discard_connection_filename  s    rn   c             C   s   |   d dS )a  
	Create the _idmap_ table.  This table has columns "old" and "new"
	containing text strings mapping old IDs to new IDs.  The old column
	is a primary key (is indexed and must contain unique entries).  The
	table is created as a temporary table, so it will be automatically
	dropped when the database connection is closed.

	This function is for internal use, it forms part of the code used
	to re-map row IDs when merging multiple documents.
	zQCREATE TEMPORARY TABLE _idmap_ (old TEXT PRIMARY KEY NOT NULL, new TEXT NOT NULL)N)r]   r^   )r   r   r   r   idmap_create  s    ro   c             C   s   |   d dS )z
	Erase the contents of the _idmap_ table, but leave the table in
	place.

	This function is for internal use, it forms part of the code used
	to re-map row IDs when merging multiple documents.
	zDELETE FROM _idmap_N)r]   r^   )r   r   r   r   idmap_reset  s    rp   c             C   s2   t | }x|tjD ]}|  qW |  dS )z
	Iterate over the tables in the database, ensure that there exists a
	custom DBTable class for each, and synchronize that table's ID
	generator to the ID values in the database.
	N)get_xmlZgetElementsByTagNameDBTableZtagNamesync_next_idr2   )r   Zxmldoctblr   r   r   
idmap_sync  s    ru   c             C   sP   |   }|d|f | }|dk	r4t|d S | }|d||f |S )a  
	From the old ID string, obtain a replacement ID string by either
	grabbing it from the _idmap_ table if one has already been assigned
	to the old ID, or by using the current value of the Table
	instance's next_id class attribute.  In the latter case, the new ID
	is recorded in the _idmap_ table, and the class attribute
	incremented by 1.

	This function is for internal use, it forms part of the code used
	to re-map row IDs when merging multiple documents.
	z&SELECT new FROM _idmap_ WHERE old == ?Nr   z!INSERT INTO _idmap_ VALUES (?, ?))r]   r^   fetchoner   ilwdcharget_next_id)r   oldrt   r]   newr   r   r   idmap_get_new  s    r{   c             C   sN   |   }|d|j|jd |jf  | d }|  |dkrFdS ||S )a>  
	Given an ilwd:char ID class, return the highest ID from the table
	for whose IDs that is the class.

	Example:

	>>> event_id = ilwd.ilwdchar("sngl_burst:event_id:0")
	>>> print(event_id)
	sngl_inspiral:event_id:0
	>>> max_id = get_max_id(connection, type(event_id))
	>>> print(max_id)
	sngl_inspiral:event_id:1054
	z7SELECT MAX(CAST(SUBSTR(%s, %d, 10) AS INTEGER)) FROM %sr   r   N)r]   r^   column_nameZindex_offset
table_namerv   rA   )r   Zid_classr]   Zmaxidr   r   r   idmap_get_max_id  s    r~   z4CREATE\s+TABLE\s+(?P<name>\w+)\s*\((?P<coldefs>.*)\)z%\s*(?P<name>\w+)\s+(?P<type>\w+)[^,]*c             C   s    |   }|d dd |D S )z5
	Return a list of the table names in the database.
	z4SELECT name FROM sqlite_master WHERE type == 'table'c             S   s   g | ]
\}|qS r   r   ).0r3   r   r   r   
<listcomp>  s    z#get_table_names.<locals>.<listcomp>)r]   r^   )r   r]   r   r   r   get_table_names  s    
r   c             C   sJ   |   }|d|f | \}tt| d }dd tt|D S )z^
	Return an in order list of (name, type) tuples describing the
	columns in the given table.
	zASELECT sql FROM sqlite_master WHERE type == 'table' AND name == ?coldefsc             S   s8   g | ]0}|  d   dkr|  d  |  d fqS )r3   )ZPRIMARYZUNIQUEZCHECKtype)	groupdictupper)r   Zcoldefr   r   r   r   )  s    z#get_column_info.<locals>.<listcomp>)	r]   r^   rv   rematch_sql_create_table_patternr   finditer_sql_coldef_pattern)r   r}   r]   	statementr   r   r   r   get_column_info   s
    
r   c          
   C   s  t  }|dkrt| }x|D ]}yt| }W n tk
rF   t}Y nX |tdd| i| d}xZt| |jD ]J\}}|j	dk	r|j	| }n
t
j| }|ttd||f |d qnW |  |ttd| tjjjtjjjd || qW |S )aV  
	Construct an XML document tree wrapping around the contents of the
	database.  On success the return value is a ligolw.LIGO_LW element
	containing the tables as children.  Arguments are a connection to
	to a database, and an optional list of table names to dump.  If
	table_names is not provided the set is obtained from get_table_names()
	NNamez%s:table)r   z%s:%s)r   Type)r   	Delimiterr   )r   ZLIGO_LWr   TableByNameKeyErrorrr   r   r   r   validcolumnsligolwtypesZFromSQLiteTypeZappendChildr   Column_end_of_columnsZTableStreamr   defaultr   )r   Ztable_namesZligo_lwr}   clsZ
table_elemr|   Zcolumn_typer   r   r   rq   ,  s$    



&,rq   c               @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd ZeZdd ZeZdd Zdd Zd S )!rr   a]	  
	A special version of the Table class using an SQL database for
	storage.  Many of the features of the Table class are not available
	here, but instead the user can use SQL to query the table's
	contents.

	The constraints attribute can be set to a text string that will be
	added to the table's CREATE statement where constraints go, for
	example you might wish to set this to "PRIMARY KEY (event_id)" for
	a table with an event_id column.

	Note:  because the table is stored in an SQL database, the use of
	this class imposes the restriction that table names be unique
	within a document.

	Also note that at the present time there is really only proper
	support for the pre-defined tables in the lsctables module.  It is
	possible to load unrecognized tables into a database from LIGO
	Light Weight XML files, but without developer intervention there is
	no way to indicate the constraints that should be imposed on the
	columns, for example which columns should be used as primary keys
	and so on.  This can result in poor query performance.  It is also
	possible to extract a database' contents to a LIGO Light Weight XML
	file even when the database contains unrecognized tables, but
	without developer intervention the column types will be guessed
	using a generic mapping of SQL types to LIGO Light Weight types.

	Each instance of this class must be connected to a database.  The
	(Python DBAPI 2.0 compatible) connection object is passed to the
	class via the connection parameter at instance creation time.

	Example:

	>>> import sqlite3
	>>> connection = sqlite3.connection()
	>>> tbl = dbtables.DBTable(AttributesImpl({u"Name": u"process:table"}), connection = connection)

	A custom content handler must be created in order to pass the
	connection keyword argument to the DBTable class when instances are
	created, since the default content handler does not do this.  See
	the use_in() function defined in this module for information on how
	to create such a content handler

	If a custom glue.ligolw.Table subclass is defined in
	glue.ligolw.lsctables whose name matches the name of the DBTable
	being constructed, the lsctables class is added to the list of
	parent classes.  This allows the lsctables class' methods to be
	used with the DBTable instances but not all of the methods will
	necessarily work with the database-backed version of the class.
	Your mileage may vary.
	c                sh   t | dsV|\}tj|d }|tjkrVtj|  G  fddd|  }|t|< |} tjj| f| S )N	tableNamer   c                   s6   e Zd Z jZ jZ jZ jZ jZ jZ j	Z	dS )z&DBTable.__new__.<locals>.CustomDBTableN)
__name__
__module____qualname__r   r   loadcolumnsconstraintsnext_idRowTypehow_to_indexr   )lscclsr   r   CustomDBTable  s   r   )hasattrr   Table	TableNamer	   r   __new__)r   argskwargsattrsr3   r   r   )r   r   r     s    

	
zDBTable.__new__c             O   s.   t jj| f|  |d| _| j | _d S )Nr   )r   r   __init__r&   r   r]   )r,   r   r   r   r   r   r     s    zDBTable.__init__c             O   s   t dS )zZ
		This method is not implemented.  See
		glue.ligolw.table.Table for more information.
		N)NotImplemented)r,   r   r   r   r   r   copy  s    zDBTable.copyc          
      sr  t j jd k	rHfddjD _fddtjD _nj_j_t	j
t	jdtj  y0dj d dt fdd	jj }W n2 tk
r } ztd
t| W d d }~X Y nX jd k	r|dj 7 }|d7 }j|  pd_ddtj ddgtj dtj }djdj|f _tjj _d S )Nc                s   g | ]}| j kr|qS r   )r   )r   r3   )r,   r   r   r     s    z+DBTable._end_of_columns.<locals>.<listcomp>c                s$   g | ]\}} j |  jkr|qS r   )columnnamesr   )r   r[   r3   )r,   r   r   r     s    )r   r   zCREATE TABLE IF NOT EXISTS z (z, c                s   d|  | f S )Nz%s %sr   )nt)	ToSQLTyper   r   <lambda>      z)DBTable._end_of_columns.<locals>.<lambda>zcolumn type '%s' not supported)r   ,?z%szINSERT INTO %s (%s) VALUES (%s))r   r   r   r   r   dbcolumnnames	enumerateZcolumntypesdbcolumntypesr   ZToSQLiteTypeZToMySQLTyper   r   r   rR   mapr   rZ   r@   r   r]   r^   maxrowidlast_maxrowidlenappend_statementoperator
attrgetterappend_attrgetter)r,   r   rC   paramsr   )r   r,   r   r     s.    
0"
zDBTable._end_of_columnsc             C   s   t j|  | j  d S )N)r   r   _end_of_rowsr   commit)r,   r   r   r   r     s    zDBTable._end_of_rowsc             C   sN   | j d k	rHt| jt| j }|d kr:| t| j d n| |d  | j S )Nr   r   )r   r~   r   r   Zset_next_id)r,   Zmax_idr   r   r   rs     s    
zDBTable.sync_next_idc             C   s    | j d| j  | j  d S )NzSELECT MAX(ROWID) FROM %sr   )r]   r^   r   rv   )r,   r   r   r   r     s    zDBTable.maxrowidc             C   s    | j d| j  | j  d S )NzSELECT COUNT(*) FROM %sr   )r]   r^   r   rv   )r,   r   r   r   __len__  s    zDBTable.__len__c             c   s8   | j  }|d| j  x|D ]}| |V  q W d S )Nz#SELECT * FROM %s ORDER BY rowid ASC)r   r]   r^   r   row_from_cols)r,   r]   valuesr   r   r   __iter__  s    

zDBTable.__iter__c             c   s8   | j  }|d| j  x|D ]}| |V  q W d S )Nz$SELECT * FROM %s ORDER BY rowid DESC)r   r]   r^   r   r   )r,   r]   r   r   r   r   __reversed__  s    

zDBTable.__reversed__c             C   s   | j | j| | dS )zV
		Standard .append() method.  This method is for intended for
		internal use only.
		N)r]   r^   r   r   )r,   rowr   r   r   _append  s    zDBTable._appendc             C   s<   | j dk	r.t|| j jt| jt|| j j|  | | dS )aT  
		Replacement for the standard .append() method.  This
		version performs on the fly row ID reassignment, and so
		also performs the function of the updateKeyMapping()
		method.  SQLite does not permit the PRIMARY KEY of a row to
		be modified, so it needs to be done prior to insertion.
		This method is intended for internal use only.
		N)r   setattrr|   r{   r   getattrr   )r,   r   r   r   r   _remapping_append  s    	
$zDBTable._remapping_appendc             C   sL   |   }x>t| j| j|D ]*\}}}|tjkr8t|}t||| qW |S )z
		Given an iterable of values in the order of columns in the
		database, construct and return a row object.  This is a
		convenience function for turning the results of database
		queries into Python objects.
		)	r   zipr   r   r   IDTypesr   rw   r   )r,   r   r   cr   vr   r   r   r   $  s    

zDBTable.row_from_colsc             C   s   t j|  d | _d | _d S )N)r   r   r2   r   r]   )r,   r   r   r   r2   4  s    zDBTable.unlinkc                sR   d  fddt j jD }|rN jd j| jf    pJd _dS )z
		Used as the second half of the key reassignment algorithm.
		Loops over each row in the table, replacing references to
		old row keys with the new values from the _idmap_ table.
		z, c             3   s>   | ]6\}}|t jkr jd ks*| jjkrd||f V  qd S )Nz.%s = (SELECT new FROM _idmap_ WHERE old == %s))r   r   r   r|   )r   ZcoltypeZcolname)r,   r   r   	<genexpr>?  s    z*DBTable.applyKeyMapping.<locals>.<genexpr>z!UPDATE %s SET %s WHERE ROWID > %dr   N)	rR   r   r   r   r]   r^   r   r   r   )r,   Zassignmentsr   )r,   r   applyKeyMapping9  s    "zDBTable.applyKeyMappingN)r   r   r   __doc__r   r   r   r   r   rs   r   r   r   r   r   r   r`   r   Z_row_from_colsr2   r   r   r   r   r   rr   X  s$   3"
$	rr   c               @   sD   e Zd ZejjZejjZejjZejjZejj	Z	ejj
Z
dd ZdS )ProcessParamsTablec             C   s6   |j d k	r&|j tjkr&td|j  t| | d S )Nzunrecognized type '%s')r   r   ZTypesr   ZElementErrorrr   r`   )r,   r   r   r   r   r`   ]  s    zProcessParamsTable.appendN)r   r   r   r	   r   r   r   r   r   r   r   r`   r   r   r   r   r   U  s   r   c               @   sN   e Zd ZejjZejjZejjZejjZejj	Z	ejj
Z
dd ZdddZdS )TimeSlideTablec                s6   ddl m  t fddt| jddd D S )zI
		Return a ditionary mapping time slide IDs to offset
		dictionaries.
		r   )offsetvectorc             3   s.   | ]&\}}t | d d |D fV  qdS )c             s   s   | ]\}}}||fV  qd S )Nr   )r   time_slide_id
instrumentoffsetr   r   r   r   r  s    z3TimeSlideTable.as_dict.<locals>.<genexpr>.<genexpr>N)r   rw   )r   r   r   )r   r   r   r   r  s    z)TimeSlideTable.as_dict.<locals>.<genexpr>zOSELECT time_slide_id, instrument, offset FROM time_slide ORDER BY time_slide_idc             S   s   | d S )Nr   r   )Ztime_slide_id_instrument_offsetr   r   r   r   r  r   z(TimeSlideTable.as_dict.<locals>.<lambda>)Zlalburst.offsetvectorr   dict	itertoolsgroupbyr]   r^   )r,   r   )r   r   as_dictk  s    zTimeSlideTable.as_dictNFc       
         s   |r  fdd|    D }n fdd|    D }t|dkrZ|rR|d S t t|dkrn|d S |dkr~t |  }x@  D ]4\}}|  }	|j|	_||	_||	_||	_	| 
|	 qW |S )af  
		Return the time_slide_id corresponding to the offset vector
		described by offsetdict, a dictionary of instrument/offset
		pairs.

		If the optional create_new argument is None (the default),
		then the table must contain a matching offset vector.  The
		return value is the ID of that vector.  If the table does
		not contain a matching offset vector then KeyError is
		raised.

		If the optional create_new argument is set to a Process
		object (or any other object with a process_id attribute),
		then if the table does not contain a matching offset vector
		a new one will be added to the table and marked as having
		been created by the given process.  The return value is the
		ID of the (possibly newly created) matching offset vector.

		If the optional superset_ok argument is False (the default)
		then an offset vector in the table is considered to "match"
		the requested offset vector only if they contain the exact
		same set of instruments.  If the superset_ok argument is
		True, then an offset vector in the table is considered to
		match the requested offset vector as long as it provides
		the same offsets for the same instruments as the requested
		vector, even if it provides offsets for other instruments
		as well.

		More than one offset vector in the table might match the
		requested vector.  If the optional nonunique_ok argument is
		False (the default), then KeyError will be raised if more
		than one offset vector in the table is found to match the
		requested vector.  If the optional nonunique_ok is True
		then the return value is the ID of one of the matching
		offset vectors selected at random.
		c                s2   g | ]*\}} t  fd d| D kr|qS )c             3   s"   | ]\}}| kr||fV  qd S )Nr   )r   r   r   )
offsetdictr   r   r     s    z>TimeSlideTable.get_time_slide_id.<locals>.<listcomp>.<genexpr>)r   items)r   idslide)r   r   r   r     s    z4TimeSlideTable.get_time_slide_id.<locals>.<listcomp>c                s   g | ]\}} |kr|qS r   r   )r   r   r   )r   r   r   r     s    r   r   N)r   r   r   r   rx   r   Z
process_idr   r   r   r`   )
r,   r   Z
create_newZsuperset_okZnonunique_okZidsr   r   r   r   r   )r   r   get_time_slide_idt  s(    &z TimeSlideTable.get_time_slide_id)NFF)r   r   r   r	   r   r   r   r   r   r   r   r   r   r   r   r   r   r   c  s   	r   c          
   C   s   |   }xt| D ]}|tkr*t| j}n|tjkrtj| j}nq|dk	r|r`tjd|  x0t	|D ]"\}}|
d||d|f  qlW qW |   dS )z
	Using the how_to_index annotations in the table class definitions,
	construct a set of indexes for the database at the given
	connection.
	Nzindexing %s table ...
z(CREATE INDEX IF NOT EXISTS %s ON %s (%s)r   )r]   r   r   r   r	   r   r4   r5   rg   rh   r^   rR   r   )r   r9   r]   r}   r   Z
index_namecolsr   r   r   build_indexes  s    
"r   c             C   s   t | } dd }|| _| S )aJ  
	Modify ContentHandler, a sub-class of
	glue.ligolw.LIGOLWContentHandler, to cause it to use the DBTable
	class defined in this module when parsing XML documents.  Instances
	of the class must provide a connection attribute.  When a document
	is parsed, the value of this attribute will be passed to the
	DBTable class' .__init__() method as each table object is created,
	and thus sets the database connection for all table objects in the
	document.

	Example:

	>>> import sqlite3
	>>> from glue.ligolw import ligolw
	>>> class MyContentHandler(ligolw.LIGOLWContentHandler):
	...	def __init__(self, *args):
	...		super(MyContentHandler, self).__init__(*args)
	...		self.connection = sqlite3.connection()
	...
	>>> use_in(MyContentHandler)

	Multiple database files can be in use at once by creating a content
	handler class for each one.
	c             S   s8   t j|d }|tkr*t| || jdS t|| jdS )Nr   )r   )r   r   r   r   r   rr   )r,   parentr   r3   r   r   r   
startTable  s    zuse_in.<locals>.startTable)r	   use_inr   )ZContentHandlerr   r   r   r   r     s    
r   )N)NFF)F)F)F)N)F)?r   r   r   r0   r   rE   r   r   r.   	threadingZxml.sax.xmlreaderr   warningsZligor   Zgluer    r   r   r   r	   r
   r   rg   
__author__r   __version__date__date__r   r   Lockr   r   rd   re   r#   r'   r\   r_   rm   rn   ro   rp   ru   r{   r~   compile
IGNORECASEr   r   r   r   rq   r   rr   r   r   r   r   r   r   r   r   r   r   <module>    sd   

7

w

@
%%
	
, ~`
&
