B
    dƏ                 @   st  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
Z
ddlmZ ddlZddlmZmZ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 ZG dd deZG dd deZedejZedZ dd Z!d$ddZ"G dd dej#Z$G dd dej%Z&G dd de&Z'G dd de&Z(d%d d!Z)e'j*e'e(j*e(iZ+d"d# 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   )
__author____date____version__)ligolw)table)	lsctables)types)utilsc             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   ]/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/ligo/lw/dbtables.pyconnection_db_typeB   s
    	r   c               @   sV   e Zd ZdZdddZedddZedd	d
Zdd Zdd Z	dd Z
dd ZdS )workingcopya  
	Manage a working copy of an sqlite database file.  This is used
	when a large enough number of manipulations are being performed on
	a database file that the total network I/O would be higher than
	that of copying the entire file to a local disk, doing the
	manipulations locally, then copying the file back.  It is also
	useful in unburdening a file server when large numbers of read-only
	operations are being performed on the same file by many different
	machines.
	NFc             C   s4   || _ |dkr|ntd| _|| _|| _|| _dS )a]	  
		filename:  the name of the sqlite database file.

		tmp_path:  the directory to use for the working copy.  If
		None (the default), the system's default location for
		temporary files is used.  If set to the special value
		"_CONDOR_SCRATCH_DIR" then the value of the environment
		variable of that name will be used (to use a directory
		literally named _CONDOR_SCRATCH_DIR set tmp_path to
		"./_CONDOR_SCRATCH_DIR").

		replace_file:  if True, filename is truncated in place
		before manipulation;  if False (the default), the file is
		not modified before use.  This is used when the original
		file is being over-written with the working copy, and it is
		necessary to ensure that a malfunction or crash (which
		might prevent the working copy from over writing the
		original) does not leave behind the unmodified original,
		which could subsequently be mistaken for valid output.

		discard:  if True the working copy is simply deleted
		instead of being copied back to the original location;  if
		False (the default) the working copy overwrites the
		original.  This is used to improve read-only operations,
		when it is not necessary to pay the I/O cost of moving an
		unmodified file a second time.  The .discard attribute can
		be set at any time while the context manager is in use,
		before the .__exit__() method is invoked.

		verbose:  print messages to stderr.

		NOTES:

		- When replace_file mode is enabled, any failures that
		  prevent the original file from being trucated are
		  ignored.  The inability to truncate the file is
		  considered non-fatal.

		- If the operation to copy the file to the working path
		  fails then a working copy is not used, the original file
		  is used in place.  If the failure that prevents copying
		  the file to the working path is potentially transient,
		  for example "permission denied" or "no space on device",
		  the code sleeps for a brief period of time and then tries
		  again.  Only after the potentially transient failure
		  persists for several attempts is the working copy
		  abandoned and the original copy used instead.

		- When the working copy is moved back to the original
		  location, if a file with the same name but ending in
		  -journal is present in the working directory then it is
		  deleted.

		- The name of the working copy can be obtained by
		  converting the workingcopy object to a string.
		Z_CONDOR_SCRATCH_DIRN)filenameosgetenvtmp_pathreplace_filediscardverbose)selfr   r   r   r   r   r   r   r   __init__c   s
    9zworkingcopy.__init__c          
   C   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 )zy
		Truncate a file to 0 size, ignoring all errors.  This is
		used internally to implement the "replace_file" feature.
		z'%s' exists, truncating ... zcannot truncate '%s': %s
Nzdone.
)
sysstderrwriter   openO_WRONLYO_TRUNC	Exceptionstrclose)r   r   fder   r   r   truncate   s    
zworkingcopy.truncate   c             C   sJ  |rt jd| |f  xtdD ]}yt| | P W q$ tk
r } zddl}ddl	}|j|j
|jfkrp |rt jd||j|j f  |dkr|rt jd|   | S |rt jd |d	 W dd}~X Y q$X q$W |rt jd
 yt| | W nD tk
rD } z$|r4t jd| |t|f  W dd}~X Y nX |S )a\  
		Copy a file to a destination preserving permission if
		possible.  If the operation fails for a non-fatal reason
		then several attempts are made with a pause between each.
		The return value is dstname if the operation was successful
		or srcname if a non-fatal failure caused the operation to
		terminate.  Fatal failures raise an exeption.
		zcopying '%s' to '%s' ... r   r   Nzwarning: attempt %d: %s:    z working with original file '%s'
zsleeping and trying again ...

   zdone.
zHwarning: ignoring failure to copy permission bits from '%s' to '%s': %s
)r   r   r    	itertoolscountshutilcopy2IOErrorerrnotimeEPERMZENOSPC	errorcodesleepcopystatr$   r%   )srcnamedstnameZattemptsr   ir(   r2   r3   r   r   r   cpy   s8    
 ,zworkingcopy.cpyc             C   s  t | jt j}| jd k	rtjdt j	| jd 	ddd  | jd| _
| j
j| _| jrptjd| j  t d}t | t | jd| @  |r| jr| j| j| jd n(| j| j| j| jd| jkr| j| _| `
n(| j| _|r| jr| j| j| jd | S )	N.r   )suffixdirzusing '%s' as workspace
i  i  )r   )r   accessr   F_OKr   tempfileNamedTemporaryFilejoinpathsplittemporary_filenametargetr   r   r   r    umaskchmodr   r)   r;   )r   Zdatabase_existsZumskr   r   r   	__enter__   s&    
4


zworkingcopy.__enter__c             C   s   | j S )N)rI   )r   r   r   r   __str__  s    zworkingcopy.__str__c          	   C   s   yt d|   W n   Y nX | j| jkrt r | js| jrXtj	d| j| jf  t
| j| j | jrztj	d yt| jd  W n   Y nX | `W dQ R X dS )a  
		Restore the working copy to its original location if the
		two are different.

		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.
		z
%s-journalzmoving '%s' to '%s' ... zdone.
wNF)Zorig_unlinkrI   r   ligolw_utilsZSignalsTrapr   r   r   r   r    r/   mover!   r&   rG   )r   exc_typeexc_valexc_tbr   r   r   __exit__  s$    
zworkingcopy.__exit__c             C   sn   | j dkr | jrtjd dS | jr8tjd| j   | }|d| j   |  | jrjtjd dS )z8
		Sets the temp_store_directory parameter in sqlite.
		Nz'sqlite temp_store_directory not changedz2setting the sqlite temp_store_directory to %s ... z"PRAGMA temp_store_directory = '%s'zdone
)r   r   r   r   r    cursorexecuter&   )r   r   rU   r   r   r   set_temp_store_directory_  s    
z$workingcopy.set_temp_store_directory)NFFF)F)r*   F)__name__
__module____qualname____doc__r   staticmethodr)   r;   rL   rM   rT   rW   r   r   r   r   r   W   s   

@2.Dr   c               @   s>   e Zd ZdZdd Zdd Zdd Zedd	 ZdddZ	dS )idmappera  
	Create and manage the _idmap_ table in an sqlite database.  This
	table has columns "table_name", "old", and "new" mapping old IDs to
	new IDs for each table.  The (table_name, old) column pair 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 class is for internal use, it forms part of the code used to
	re-map row IDs when merging multiple documents.
	c             C   sF   || _ | j  | _y| jd W n tjk
r8   Y nX |   d S )NzCREATE TEMPORARY TABLE _idmap_ (table_name TEXT NOT NULL, old INTEGER NOT NULL, new INTEGER NOT NULL, PRIMARY KEY (table_name, old)))r   rU   rV   sqlite3ZOperationalErrorsync)r   r   r   r   r   r     s    zidmapper.__init__c             C   s   | j d dS )zN
		Erase the contents of the _idmap_ table, but leave the
		table in place.
		zDELETE FROM _idmap_N)rU   rV   )r   r   r   r   reset  s    zidmapper.resetc             C   s4   t | j}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_xmlr   getElementsByTagNameDBTabletagNamesync_next_idunlink)r   xmldoctblr   r   r   r_     s    
zidmapper.syncc             C   sF   |  d||f |  }|dk	r(|d S | }|  d|||f |S )aP  
		From the old ID, obtain a replacement ID 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.
		z:SELECT new FROM _idmap_ WHERE table_name == ? AND old == ?Nr   z$INSERT INTO _idmap_ VALUES (?, ?, ?))rV   fetchoneget_next_id)rU   
table_nameoldrh   newr   r   r   get_new  s    
zidmapper.get_newFc             C   sh   | tjj}x<t|D ]0\}}|r@tjdd| t|   |	  qW |r\tjd | 
  d S )Nzupdating IDs: %d%%g      Y@zupdating IDs: 100%
)rb   r   Tablerd   	enumerater   r   r    lenapplyKeyMappingr`   )r   rg   r   Ztable_elemsr:   rh   r   r   r   
update_ids  s    zidmapper.update_idsN)F)
rX   rY   rZ   r[   r   r`   r_   r\   rn   rs   r   r   r   r   r]   y  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   ).0rH   r   r   r   
<listcomp>  s    z#get_table_names.<locals>.<listcomp>)rU   rV   )r   rU   r   r   r   get_table_names  s    
rv   c       
   
   C   sR  t  }|dkrt| }x2|D ](}yt| }W n tk
rJ   t}Y nX |tdd| i| d}i }|jdk	rx|jD ]}||tj	
|< qzW xx| D ]l\}}	|jdk	ry|| }W n tk
r   tdY nX |j| }	n
tj|	 }	|t	t||	d qW |  |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invalid column)rw   Type)rw   	Delimiterrx   )r   ZLIGO_LWrv   TableByNameKeyErrorrc   r   validcolumnsr   ColumnZ
ColumnNameget_column_info
ValueErrorligolwtypesZFromSQLiteTypeZappendChild_end_of_columnsTableStreamry   defaultrx   )
r   Ztable_namesZligo_lwrk   clsZ
table_elemZdestriprH   column_nameZcolumn_typer   r   r   ra     s4    



,ra   c                   s   e Zd Z fddZ  ZS )DBTableStreamc                s*   t t|   t| jdr&| jj  d S )Nr   )superr   
endElementhasattrZ
parentNoder   commit)r   )	__class__r   r   r   #  s    zDBTableStream.endElement)rX   rY   rZ   r   __classcell__r   r   )r   r   r   "  s   r   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 )!rc   aL	  
	A 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 ligo.lw.Table subclass is defined in ligo.lw.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	tableNamerw   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)
rX   rY   rZ   r   r|   loadcolumnsconstraintsnext_idRowTypehow_to_indexr   )lscclsr   r   CustomDBTablel  s   r   )r   r   ro   	TableNamer	   rz   __new__)r   argskwargsattrsrH   r   r   )r   r   r   \  s    

	
zDBTable.__new__c             O   s.   t jj| f|  |d| _| j | _d S )Nr   )r   ro   r   popr   rU   )r   r   r   r   r   r   r   ~  s    zDBTable.__init__c             O   s   t dS )zV
		This method is not implemented.  See ligo.lw.table.Table
		for more information.
		N)NotImplementedError)r   r   r   r   r   r   copy  s    zDBTable.copyc          
      sh  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| 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   )rt   rH   )r   r   r   ru     s    z+DBTable._end_of_columns.<locals>.<listcomp>c                s$   g | ]\}} j |  jkr|qS r   )columnnamesr   )rt   r:   rH   )r   r   r   ru     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),?z%szINSERT INTO %s (%s) VALUES (%s))r   ro   r   r   r   dbcolumnnamesrp   ZcolumntypesZdbcolumntypesr   ZToSQLiteTypeZToMySQLTyper   r   rw   rD   mapr{   r   r%   r   rU   rV   remap_first_rowidrq   append_statementoperator
attrgetterappend_attrgetter)r   	statementr(   paramsr   )r   r   r   r     s.    
0"
zDBTable._end_of_columnsc             C   sH   | j d| jf | j  \}tt| d }dd tt	|D S )z\
		Return an in order list of (name, type) tuples describing
		the columns in this 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 )rH   )ZPRIMARYZUNIQUEZCHECKtype)	groupdictupper)rt   Zcoldefr   r   r   ru     s    z+DBTable.get_column_info.<locals>.<listcomp>)
rU   rV   rw   ri   rematch_sql_create_table_patternr   finditer_sql_coldef_pattern)r   r   r   r   r   r   r~     s    zDBTable.get_column_infoc             C   s`   | j d k	rZ| jd| j j| jf  d }|d k	rZt| j |d }|| j krZ| | | j S )NzSELECT MAX(%s) FROM %sr   r   )r   rU   rV   r   rw   ri   r   Zset_next_id)r   Zmaxidr   r   r   re     s    
"

zDBTable.sync_next_idc             C   s    | j d| j  | j  d S )NzSELECT MAX(ROWID) FROM %sr   )rU   rV   rw   ri   )r   r   r   r   maxrowid  s    zDBTable.maxrowidc             C   s    | j d| j  | j  d S )NzSELECT COUNT(*) FROM %sr   )rU   rV   rw   ri   )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   rU   rV   rw   row_from_cols)r   rU   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   rU   rV   rw   r   )r   rU   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)rU   rV   r   r   )r   rowr   r   r   _append  s    zDBTable._appendc          
   C   sd   | j dk	r4t|| j jt| j| jt|| j j|  | | | j	dkr`| 
 | _	| j	dk	s`t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]   rn   rU   rw   getattrr   r   r   AssertionError)r   r   r   r   r   _remapping_append  s    	
*


zDBTable._remapping_appendc             C   s2   |   }x$t| j|D ]\}}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   r   r   cvr   r   r   r     s    zDBTable.row_from_colsc             C   s   t j|  d | _d | _d S )N)r   ro   rf   r   rU   )r   r   r   r   rf     s    zDBTable.unlinkc          	   C   s   | j dkrdS g }xf| jD ]\}| |}y
|j}W n tk
rH   wY nX | jdk	rb|| jjkrbq|d|||f  qW d|}|r| j	
d| j|| j f  d| _ 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.
		NzU%s = (SELECT new FROM _idmap_ WHERE _idmap_.table_name == "%s" AND _idmap_.old == %s)z, z"UPDATE %s SET %s WHERE ROWID >= %d)r   r   ZgetColumnByNamerk   r   r   r   appendrD   rU   rV   rw   )r   ZassignmentsZcolnamecolumnrk   r   r   r   rr     s     



zDBTable.applyKeyMappingN)rX   rY   rZ   r[   r   r   r   r   r~   re   r   r   r   r   r   r   r   r   Z_row_from_colsrf   rr   r   r   r   r   rc   )  s$   2"
$
rc   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 )CoincMapTablec             C   s&   | j d k	r"| jd| j f d | _ d S )Na  UPDATE coinc_event_map SET event_id = (SELECT new FROM _idmap_ WHERE _idmap_.table_name == coinc_event_map.table_name AND old == event_id), coinc_event_id = (SELECT new FROM _idmap_ WHERE _idmap_.table_name == 'coinc_event' AND old == coinc_event_id) WHERE ROWID >= ?)r   rU   rV   )r   r   r   r   rr   K  s    
zCoincMapTable.applyKeyMappingN)rX   rY   rZ   r	   r   r   r|   r   r   r   r   rr   r   r   r   r   r   C  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 )zJ
		Return a dictionary mapping time slide IDs to offset
		dictionaries.
		r   )offsetvectorc             3   s*   | ]"\}}|  d d |D fV  qdS )c             s   s   | ]\}}}||fV  qd S )Nr   )rt   time_slide_id
instrumentoffsetr   r   r   	<genexpr>c  s    z3TimeSlideTable.as_dict.<locals>.<genexpr>.<genexpr>N)r   )rt   r   r   )r   r   r   r   c  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   c  r   z(TimeSlideTable.as_dict.<locals>.<lambda>)Zlalburstr   dictr-   groupbyrU   rV   )r   r   )r   r   as_dictY  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   )rt   r   r   )
offsetdictr   r   r     s    z>TimeSlideTable.get_time_slide_id.<locals>.<listcomp>.<genexpr>)r   items)rt   r   slide)r   r   r   ru     s    z4TimeSlideTable.get_time_slide_id.<locals>.<listcomp>c                s   g | ]\}} |kr|qS r   r   )rt   r   r   )r   r   r   ru     s    r   r   N)r   r   rq   r{   rj   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_ide  s(    &z TimeSlideTable.get_time_slide_id)NFF)rX   rY   rZ   r	   r   r   r|   r   r   r   r   r   r   r   r   r   r   r   Q  s   r   Fc          
   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|  x.| D ]"\}}|	d||d
|f  qjW 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   )rU   rv   rz   r   r	   r   r   r    r   rV   rD   r   )r   r   rU   rk   r   Z
index_namecolsr   r   r   build_indexes  s    
"r   c             C   s0   t | } | jfdd}dd }|| _|| _| S )aI  
	Modify ContentHandler, a sub-class of
	ligo.lw.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 ligo.lw 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   s0   |j tjj kr$|  t||S || ||S )N)rd   r   ro   r   r   config)r   parentr   Z__orig_startStreamr   r   r   startStream  s    zuse_in.<locals>.startStreamc             S   s8   t j|d }|tkr*t| || jdS t|| jdS )Nrw   )r   )r   ro   r   rz   r   rc   )r   r   r   rH   r   r   r   
startTable  s    zuse_in.<locals>.startTable)r	   use_inr   r   )ZContentHandlerr   r   r   r   r   r     s    
r   )N)F)-r[   r-   r   r   r   r/   signalr^   r   rB   	threadingZxml.sax.xmlreaderr   warnings r   r   r   r   r   r	   r
   r   r   rO   r   objectr   r]   compile
IGNORECASEr   r   rv   ra   r   r   ro   rc   r   r   r   r   rz   r   r   r   r   r   <module>    sJ     $b
	
5  c
&
