
    ZThP                        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mZmZmZmZmZ d dlZd dlmZ 	 d d	lmZmZmZmZmZmZmZ d dl m!Z" d dl#m$Z$ d dl%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l0m1Z1 d dl2m3Z3 d dl4m5Z5 ejl                  e3jn                  ejp                  e3jr                  ejt                  e3jr                  ejv                  e3jr                  ejx                  e3jz                  ej|                  e3j~                  ej                  e3j~                  ej                  e3j~                  ej                  e3j                  ej                  e3j                  ej                  e3j                  ej                  e3j                  iZJ G d de      ZKdZL edg d      ZMddddddZNdeOdeOfdZP G d d       ZQy# e$ rZ ed
      edZ[ww xY w)!    N)
namedtuple)
DictWriter)datetime)Enum)Path)DictListOptionalSequenceTextIOUnion)to_datetime)ChannelObject
RootObjectTdmsChannelTdmsFile	TdmsGroup
TdmsWritertypeszThe npTDMS package is required to use the TDMS upload service. Please include this dependency in your project by specifying `sift-stack-py[tdms]`.)channel_fqn)metadata_dict_to_pb)
DataColumn
TimeColumn)	CsvConfig)CsvUploadService)DataImportService)NamedTemporaryFile)TimeFormatType)ChannelDataType)SiftRestConfigc                       e Zd ZdZdZy)TdmsTimeFormatwaveformtime_channelN)__name__
__module____qualname__WAVEFORMTIME_CHANNEL     ]/home/www/backend.miabetepe.com/venv/lib/python3.12/site-packages/sift_py/data_import/tdms.pyr"   r"   7   s    H!Lr+   r"   Time_TdmsChannel
group_namename	data_typedata
properties_)"\`~|input_stringreturnc                 R    | j                  t        j                  t                    S )a  
    Removes the characters ", \, `, ~, and | from the input string.

    See https://docs.siftstack.com/docs/data-model/assets-channels-runs#assets-and-channels

    Args:
        input_string: The string to sanitize.

    Returns:
        The sanitized string.
    )	translatestr	maketransCHARACTER_REPLACEMENTS)r;   s    r,   sanitize_stringrB   P   s     !!#--0F"GHHr+   c                      e Zd ZU dZeed<   defdZdddddej                  dfde
eef   ded	ed
ededee   dee   dededefdZde
eef   deded	ededee   dee   dedefdZde
eef   deded	ededee   dee   defdZde
eef   deded	ededee   dee   defdZddej.                  fdee
eef      ded	edee   dee   dedefdZy)TdmsUploadServicez'
    Service to upload TDMS files.
    _csv_upload_service	rest_confc                 $    t        |      | _        y )N)r   rE   )selfrF   s     r,   __init__zTdmsUploadService.__init__f   s    #3I#> r+   FNpath
asset_nameprefix_channel_with_groupgroup_into_componentsignore_errorsrun_namerun_idtdms_time_formatinclude_metadatar<   c
                 ~   |rt        j                  dt               |}t        |t              rt        |      n|}
|
j                         st        d| d      |	r|s|st        d      |r|rt        d      d }t        |      }t        |j                  |      }|r| j                  j                  ||      }d}n| j                  j                  ||       t        dd	
      5 }| j!                  ||||||||      }| j                  j#                  |j$                  |      }ddd       |S # 1 sw Y   S xY w)a]  
        Uploads the TDMS file pointed to by `path` to the specified asset.

        Args:
            path: The path to the file to upload.
            asset_name: The name of the asset to upload to.
            prefix_channel_with_group: Set to True if you want to prefix the channel name with TDMS group.
                This can later be used to group into folders in the Sift UI. Default is False.
            ignore_errors: If True will skip channels without timing information. Default is False.
            run_name: The name of the run to create for this data. Default is None.
            run_id: The id of the run to add this data to. Default is None.
            tdms_time_format: Specify how timing information is encoded in the file. Default is WAVEFORM.
                If using the TIME_CHANNEL format, timestamps should use the LabVIEW/TDMS epoch (number of
                seconds since 01/01/1904 00:00:00.00 UTC).
            include_metadata: Whether to include TDMS file metadata as Run metadata.

        Returns:
            The DataImportService used to get the status of the import.
        z`group_into_components` has been renamed to `prefix_channel_with_group` to reflect the deprecation of Sift Channel components. `component` will be removed in 1.0.0. See docs for more details: https://docs.siftstack.com/docs/glossary#componentzProvided path, 'z$', does not point to a regular file.z%Metadata can only be included in Runsz0Must specify either run_name or run_id, not bothc                     t        | t        j                        rt        |       S t        | t              r| j                         S t        d|        )z%Convert datetime metadata to strings.z#Unable to parse value as metadata: )
isinstancenp
datetime64r?   r   	isoformat
ValueError)values    r,   parse_datetimez0TdmsUploadService.upload.<locals>.parse_datetime   sD    eR]]3u:%x0 ??,,$'J5'%RSSr+   Nwtz.csv.gz)modesuffix)warningswarnFutureWarningrU   r?   r   is_file	ExceptionrY   r   r   r4   rE   _create_run_add_metadata_to_runr   _convert_to_csvuploadr1   )rH   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   
posix_pathr[   	tdms_filemetadata	temp_file
csv_configdata_imports                    r,   rg   zTdmsUploadService.uploadi   sU   > !MM` 	 )>%#-dC#8T$Zd
!!#.tf4XYZZ h !HIIF !STTT !I*9+?+?PH 11==hQ ((==fhOT)< 	V	--) 	J 2299)..*UK	V 	V s   )?D22D<src_pathdst_filec	           	          |t         j                  k(  r| j                  }	n.|t         j                  k(  r| j                  }	nt        d|        |	|||||||      S )a  Converts the TDMS file to a temporary CSV on disk that we will upload.

        Args:
            src_path: The source path to the TDMS file.
            dst_file: The output CSV file.
            asset_name: The name of the asset to upload to.
            prefix_channel_with_group: Set to True if you want to prefix the channel name with TDMS group.
                This can later be used to group into folders in the Sift UI.
            ignore_errors: If True will skip channels without timing information.
            run_name: The name of the run to create for this data.
            run_id: The id of the run to add this data to.
            tdms_time_format: Specify how timing information is encoded in the file.

        Returns:
            The CSV config for the import.
        zUnknown TDMS time format: )r"   r(   _convert_waveform_tdms_to_csvr)   !_convert_time_channel_tdms_to_csvrc   )
rH   rn   ro   rK   rL   rN   rO   rP   rQ   convert_funcs
             r,   rf   z!TdmsUploadService._convert_to_csv   sm    6 ~666==L!<!<<AAL89I8JKLL%
 	
r+   c                 8   dt         dt        fd}t        |      }	|	j                         }
g }|
D ]  }|j	                         D ]  } ||      r[t        t        |j                        t        |j                        |j                  |j                        }|j                  |       f|r&t        |j                   d|j                   d       t        |j                   d|j                   d        |st        d|       t        d	
      5 }t        |j                        5 }t!        |	j                        }|j#                  |g|
z   |z          ddd       t        |j                        }|j%                  dd      }|j'                  |d       |j)                          ddd       j                         D cg c]  }|j	                         D ]  }|  }}}| j+                  |||||      S # 1 sw Y   xY w# 1 sw Y   _xY wc c}}w )a  Converts the TDMS file to a temporary CSV on disk using channel waveform properties.

        Args:
            src_path: The source path to the TDMS file.
            dst_file: The output CSV file.
            asset_name: The name of the asset to upload to.
            prefix_channel_with_group: Set to True if you want to prefix the channel name with TDMS group.
                This can later be used to group into folders in the Sift UI.
            ignore_errors: If True will skip channels without timing information.
            run_name: The name of the run to create for this data.
            run_id: The id of the run to add this data to.

        Returns:
            The CSV config for the import.
        channelr<   c                 f    t        d| j                  v d| j                  v d| j                  v g      S )z=Returns True if the TDMS Channel contains timing information.wf_incrementwf_start_timewf_start_offset)allr4   )ru   s    r,   contains_timingzHTdmsUploadService._convert_waveform_tdms_to_csv.<locals>.contains_timing	  s>    "g&8&88#w'9'99%););; r+   )groupru   r3   r4   :z/ does not contain timing information. Skipping.zn does not contain timing information. Set `ignore_errors` to True to skip channels without timing information.zNo valid channels found in w)r]   NT)
time_indexabsolute_timezutf-8)encoding)channelsrK   rL   rO   rP   )r   boolr   groupsr   r   rB   r0   r1   r3   r4   appendprintrc   r   r   r   write_segmentas_dataframeto_csvclose_create_csv_config)rH   rn   ro   rK   rL   rN   rO   rP   r{   src_fileoriginal_groupsvalid_channelsr|   ru   new_channelftdms_writerroot_objectfiltered_tdms_filedfvalid_tdms_channelss                        r,   rq   z/TdmsUploadService._convert_waveform_tdms_to_csv   s.   4	[ 	T 	 H%"//+.0$ 	E >>+ "7+"/-g.@.@A / =$\\#*#5#5	#K #))+6$$zzl!GLL>9hi ($zzl!GLL> :g g 	* 9(DEE  S) 	QAFF# \{()<)<=));-/*IN*Z[\ "*!&&!1#00DPT0UBIIhI1
 NN	 "4!:!:!<
ENNL\
AHG

 
 &&(!&? ' 
 	
#\ \	 	
s+   H
+.G>AH
H>H	H

Hc           
         dt         dt        t           fd}t        |      }	i }
g }|	j	                         D ]  }t        |j                        } ||      }t        |      dk7  r>t        |      dkD  r|j                   dnd}|rt        | d       _t        | d      |d	   }g }|j                         D ]8  }||k(  r\t        }t        |j                        j                  d
      }|j                  d      |j                   j#                  d       z   dz   }nt        |j                        t        |j                        k7  r;d|j                   d|j                   }|rt        | d       t        | d      t        |j                        }|j                  }t%        |||j&                  ||j(                        }|j+                  |       ||k7  s(|j+                  |       ; t        |      dkD  r||
|<   |j                   d}|rt        | d       t        | d       |
st        d|       t        g|D cg c]  }|j                   c}z   }t-        ||      }|j/                          g }|
j1                         D ]a  }t        |d	   j                        }t3        |      D ]9  }|j+                  |D ci c]  }|j                  |j                  |    c}       ; c |j5                  |       |j7                          | j9                  |||||t:        j<                        S c c}w c c}w )a  Converts the TDMS file to a temporary CSV using time channels in each group.

        Args:
            src_path: The source path to the TDMS file.
            dst_file: The output CSV file.
            asset_name: The name of the asset to upload to.
            prefix_channel_with_group: Set to True if you want to prefix the channel name with TDMS group.
                This can later be used to group into folders in the Sift UI.
            ignore_errors: If True will skip channels without timing information.
            run_name: The name of the run to create for this data.
            run_id: The id of the run to add this data to.

        Returns:
            The CSV config for the import.
        r|   r<   c                     | j                         D cg c]"  }|j                  t        j                  k(  s!|$ c}S c c}w )zReturns the time channels.)r   r2   r   	TimeStamp)r|   ru   s     r,   get_time_channelszNTdmsUploadService._convert_time_channel_tdms_to_csv.<locals>.get_time_channelsd  s1    +0>>+;dw?P?PTYTcTc?cGddds   "==   z$ contains more than one time channelzno time channelsz. Skipping.z1. Set `ignore_errors` to True to skip this group.r   UTCz%Y-%m-%dT%H:%M:%S.%fc                     | dz  dS )Ni  03dr*   )nss    r,   <lambda>zETdmsUploadService._convert_time_channel_tdms_to_csv.<locals>.<lambda>  s    BIc? r+   ZzLength mismatch between z and z3. Set `ignore_errors` to True to skip this channel.r/   z$ does not contain any valid channelszNo valid groups remaining in )r   rK   rL   rO   rP   time_format)r   r	   r   r   r   rB   r1   lenr   rc   r   TIME_CHANNEL_NAMEr   r3   tz_localizestrftime
nanosecondmapr.   r2   r4   r   r   writeheadervaluesrange	writerowsr   r   r   ABSOLUTE_RFC3339)rH   rn   ro   rK   rL   rN   rO   rP   r   r   valid_groupsall_tdms_channelsr|   updated_group_nametime_channelsmsgr$   updated_channelsru   updated_channel_namer3   updated_channelheaders
csv_writerrowsn_pointsis                              r,   rr   z3TdmsUploadService._convert_time_channel_tdms_to_csvJ  s   4	eY 	e43D 	e H% 7902__& <	_E!0!<-e4M=!Q& =)A- zzl"FG+ 
 !SE-.#se+\$]^^(+L! >>+ !>l*+<(&w||4@@GD&<=//--.KLM  <,,-W\\1BB 89J9J8K5QXQ]Q]P^_(!SE"56$"+#&%'Z [#  ,;7<<+H("<<D".1-%//&11# !''8l*%,,_=C!>F #$q(3C/0$HI SE-.#se+\$]^^y<	_| ;H:FGG %%EV(W'(WW'2
  , 3 3 5 	]+A.334H8_ ]JZ[wW\\7<<?:[\]	] 	T"
 	&&&!&?&77 ' 
 	
 )X \s   M!Mr   r   c           	      J   i }d}t        |      D ]  \  }	}
	 t        |
j                     j                  d      }|$t        |
j                   d|
j                         t        |r-|
j                  r!t        |
j                  |
j                        n|
j                  ||
j                  j                  dd      |
j                  j                  d	      xs d
      }||||	z   <    ||t        |d      |d}|||d<   |||d<   t        |      S # t        $ r d}Y w xY w)a  Construct a CsvConfig based on metadata within the TDMS file.

        Args:
            channels: The collection of channels.
            asset_name: The name of the asset.
            prefix_channel_with_group: Set to True if you want to prefix the channel name with TDMS group.
                This can later be used to group into folders in the Sift UI.
            run_name: The name of the run to create for this data. Default is None.
            run_id: The id of the run to add this data to. Default is None.
            time_format: The CSV time format. Default is ABSOLUTE_DATETIME.

        Returns:
            The CSV config.
           T)
api_formatNz data type not supported: )r1   	componentdescription unit_string)r1   r2   r   unitsr   )formatcolumn_number)rK   first_data_rowtime_columndata_columnsrO   rP   )	enumerateTDMS_TO_SIFT_TYPESr2   as_human_strKeyErrorrc   r1   r   r0   _channel_fqnr4   getr   r   )rH   r   rK   rL   rO   rP   r   data_configfirst_data_columnr   ru   r2   channel_configconfig_infos                 r,   r   z$TdmsUploadService._create_csv_config  sT   . .0#H- 	@JAw!.w/@/@ANNZ^N_	  7<<.0J7K\K\J] ^__',1C1C "w||w?Q?QR\\##..22="E((,,];ArN 2@K)A-.%	@* %/%" (
 &.K
#$*K!%%C  ! 	!s   #DD"!D")r%   r&   r'   __doc__r   __annotations__r    rI   r"   r(   r   r?   r   r   r
   r   rg   r   r   rf   rq   rr   r   ABSOLUTE_DATETIMEr   r   r.   r   r*   r+   r,   rD   rD   _   sx    *)?. ? +0&+#"& $+9+B+B!&XCIX X $(	X
  $X X 3-X X )X X 
Xt*
T	"*
 *
 	*

 $(*
 *
 3-*
 *
 )*
 
*
XY
T	"Y
 Y
 	Y

 $(Y
 Y
 3-Y
 Y
 
Y
v@
T	"@
 @
 	@

 $(@
 @
 3-@
 @
 
@
N #' $&4&F&F>&5l!:;<>& >& $(	>&
 3->& >& $>& 
>&r+   rD   )Rr_   collectionsr   csvr   r   enumr   pathlibr   typingr   r	   r
   r   r   r   numpyrV   pandasr   nptdmsr   r   r   r   r   r   r   ImportErroreRuntimeErrorsift_py._internal.channelr   r   sift_py._internal.metadatar   sift_py.data_import._configr   r   sift_py.data_import.configr   sift_py.data_import.csvr   sift_py.data_import.statusr   sift_py.data_import.tempfiler   sift_py.data_import.time_formatr   sift_py.ingestion.channelr   sift_py.restr    BooleanBOOLInt8INT_32Int16Int32Int64INT_64Uint8UINT_32Uint16Uint32Uint64UINT_64SingleFloatFLOATDoubleFloatDOUBLEStringSTRINGr   r"   r   r.   rA   r?   rB   rD   r*   r+   r,   <module>r      s    "     @ @     B : > 0 4 8 ; : 5 ' 
MM?''	JJ&&	KK''	KK''	KK''	KK((	LL/))	LL/))	LL/))	,,	--	LL/((  "T "  
 .*cd 

			 I# I# Ik& k&S  
	^ s   G G	GG