11import os
2+ import threading
3+ _chdir_lock = threading .Lock ()
24import numpy as np
35from typing import List , Tuple
46from .native_fisher_py_backend import *
@@ -38,15 +40,21 @@ class RawFile(object):
3840 A high-level wrapper to provide a drop-in replacement for fisher_py.RawFile
3941 """
4042 def __init__ (self , path : str ):
41- """
42- Open a Thermo RAW file.
43- """
4443 self ._path = path
4544 real_path = os .path .realpath (path )
4645 if not os .path .isfile (real_path ):
4746 raise FileNotFoundError (f'No raw file with path "{ path } " found.' )
48- res = open_raw_file (real_path )
49- if res != 0 :
47+
48+ dll_dir = os .path .dirname (__file__ )
49+ with _chdir_lock :
50+ original_cwd = os .getcwd ()
51+ try :
52+ os .chdir (dll_dir )
53+ self ._handle = open_raw_file (real_path )
54+ finally :
55+ os .chdir (original_cwd )
56+
57+ if getattr (self , "_handle" , - 1 ) < 0 :
5058 raise RawFileException (f"Could not open RAW file: { path } " )
5159 self ._is_open = True
5260
@@ -59,7 +67,7 @@ def _raw_file_access(self):
5967 return self
6068
6169 def select_instrument (self , device_type : int , device_number : int ):
62- select_instrument (device_type , device_number )
70+ select_instrument (self . _handle , device_type , device_number )
6371
6472 def average_scans (self , start , end ): return None
6573 def average_scans_in_scan_range (self , start , end , options ): return None
@@ -68,14 +76,14 @@ def default_mass_options(self): return MassOptions()
6876 def dispose (self ): self .close ()
6977 def get_all_instrument_names_from_instrument_method (self ): return []
7078 def get_instrument_method (self , index ):
71- return get_instrument_method (index )
79+ return get_instrument_method (self . _handle , index )
7280 def get_instrument_methods_count (self ) -> int :
73- return get_instrument_method_count ()
81+ return get_instrument_method_count (self . _handle )
7482 def get_instrument_type (self ): return 0
7583 def get_segment_event_table (self ): return []
7684 def has_instrument_method (self ): return self .get_instrument_methods_count () > 0
7785 def is_centroid_scan_from_scan_number (self , scan_number ):
78- return is_centroid (scan_number )
86+ return is_centroid (self . _handle , scan_number )
7987 def refresh_view_of_file (self ): pass
8088 @property
8189 def selected_instrument (self ): return 0
@@ -98,31 +106,31 @@ def path(self) -> str:
98106
99107 @property
100108 def number_of_scans (self ) -> int :
101- return get_num_scans ()
109+ return get_num_scans (self . _handle )
102110
103111 @property
104112 def first_scan (self ) -> int :
105- return get_first_scan ()
113+ return get_first_scan (self . _handle )
106114
107115 @property
108116 def last_scan (self ) -> int :
109- return get_last_scan ()
117+ return get_last_scan (self . _handle )
110118
111119 @property
112120 def file_name (self ) -> str :
113- return get_file_name ()
121+ return get_file_name (self . _handle )
114122
115123 @property
116124 def creation_date (self ) -> str :
117- return get_creation_date ()
125+ return get_creation_date (self . _handle )
118126
119127 @property
120128 def computer_name (self ) -> str :
121- return get_computer_name ()
129+ return get_computer_name (self . _handle )
122130
123131 @property
124132 def creator_id (self ) -> str :
125- return get_creator_id ()
133+ return get_creator_id (self . _handle )
126134
127135 def get_instrument_data (self ) -> InstrumentData :
128136 return InstrumentData ()
@@ -165,21 +173,21 @@ def include_reference_and_exception_data(self, value: bool):
165173
166174 @property
167175 def is_open (self ) -> bool :
168- return is_open ()
176+ return is_open (self . _handle )
169177
170178 @property
171179 def is_error (self ) -> bool :
172- return is_error ()
180+ return is_error (self . _handle )
173181
174182 @property
175183 def in_acquisition (self ) -> bool :
176- return in_acquisition ()
184+ return in_acquisition (self . _handle )
177185
178186 def retention_time_from_scan_number (self , scan_number : int ) -> float :
179- return get_scan_rt (scan_number )
187+ return get_scan_rt (self . _handle , scan_number )
180188
181189 def scan_number_from_retention_time (self , rt : float ) -> int :
182- return get_scan_number_from_rt (rt )
190+ return get_scan_number_from_rt (self . _handle , rt )
183191
184192 def get_scan_event_for_scan_number (self , scan_number : int ):
185193 from .data .classes import ScanEvent
@@ -188,21 +196,21 @@ def get_scan_event_for_scan_number(self, scan_number: int):
188196 def get_status_log_for_retention_time (self , rt : float ):
189197 from .data .classes import LogEntry
190198 scan = self .scan_number_from_retention_time (rt )
191- return LogEntry (get_status_log_values (scan ))
199+ return LogEntry (get_status_log_values (self . _handle , scan ))
192200
193201 def get_status_log_for_scan_number (self , scan_number : int ):
194202 from .data .classes import LogEntry
195- return LogEntry (get_status_log_values (scan_number ))
203+ return LogEntry (get_status_log_values (self . _handle , scan_number ))
196204
197205 def get_scan_event_string_for_scan_number (self , scan_number : int ):
198- return get_scan_event_string (scan_number )
206+ return get_scan_event_string (self . _handle , scan_number )
199207
200208 def get_centroid_stream (self , scan_number : int , include_ref_peaks : bool = False ):
201209 from .native_fisher_py_backend import get_centroid_stream
202210 from .data .classes import CentroidStream
203211 import numpy as np
204212
205- masses , intensities , baselines , noises , charges , bp_noise , bp_res = get_centroid_stream (scan_number , 1000000 )
213+ print ( f"Calling get_centroid_stream with handle= { self . _handle } , scan= { scan_number } " ); masses , intensities , baselines , noises , charges , bp_noise , bp_res = get_centroid_stream (self . _handle , scan_number , 1000000 )
206214
207215 return CentroidStream (
208216 masses = np .array (masses ),
@@ -218,13 +226,13 @@ def get_centroid_stream(self, scan_number: int, include_ref_peaks: bool = False)
218226 def get_segmented_scan_from_scan_number (self , scan_number : int , stats = None ):
219227 from .native_fisher_py_backend import get_spectrum
220228 from .data .classes import SegmentedScan
221- masses , intensities = get_spectrum (scan_number , 1000000 )
229+ masses , intensities = get_spectrum (self . _handle , scan_number , 1000000 )
222230 return SegmentedScan (masses = masses , intensities = intensities )
223231
224232 def get_scan_stats_for_scan_number (self , scan_number : int ):
225233 from .data .classes import ScanStatistics
226234 from .native_fisher_py_backend import get_scan_stats
227- data = get_scan_stats (scan_number )
235+ data = get_scan_stats (self . _handle , scan_number )
228236 return ScanStatistics (
229237 start_time = data [0 ],
230238 low_mass = data [1 ],
@@ -251,48 +259,48 @@ def get_chromatogram_data(self, settings, start_scan, end_scan, tolerance = None
251259 starts = [float (r .low ) for r in s .mass_ranges ]
252260 ends = [float (r .high ) for r in s .mass_ranges ]
253261
254- times , intensities = get_chromatogram (trace_type , filter_str , starts , ends , start_scan , end_scan , 1000000 )
262+ times , intensities = get_chromatogram (self . _handle , trace_type , filter_str , starts , ends , start_scan , end_scan , 1000000 )
255263 all_times .append (times )
256264 all_intensities .append (intensities )
257265 all_scans .append ([]) # Empty scans for now
258266
259267 return ChromatogramData (all_times , all_intensities , all_scans )
260268
261269 def get_instrument_count_of_type (self , device_type ):
262- return get_instrument_count_of_type (device_type )
270+ return get_instrument_count_of_type (self . _handle , device_type )
263271
264272 def get_trailer_extra_information (self , scan_number ):
265273 from .data .classes import LogEntry
266274 labels = [h .label for h in self .get_trailer_extra_header_information ()]
267- return LogEntry (get_trailer_extra_values (scan_number ), labels )
275+ return LogEntry (get_trailer_extra_values (self . _handle , scan_number ), labels )
268276
269277 def get_trailer_extra_header_information (self ):
270278 from .data .classes import HeaderItem
271- return [HeaderItem (h ) for h in get_trailer_extra_header ()]
279+ return [HeaderItem (h ) for h in get_trailer_extra_header (self . _handle )]
272280
273281 def get_trailer_extra_values (self , scan_number , formatted = False ):
274- return get_trailer_extra_values (scan_number )
282+ return get_trailer_extra_values (self . _handle , scan_number )
275283
276284 def get_status_log_header_information (self ):
277285 from .data .classes import HeaderItem
278- return [HeaderItem (h ) for h in get_status_log_header ()]
286+ return [HeaderItem (h ) for h in get_status_log_header (self . _handle )]
279287
280288 def get_status_log_values (self , scan_number , formatted = False ):
281289 from .data .classes import LogEntry
282290 labels = [h .label for h in self .get_status_log_header_information ()]
283- return LogEntry (get_status_log_values (scan_number ), labels )
291+ return LogEntry (get_status_log_values (self . _handle , scan_number ), labels )
284292
285293 def get_status_log_entries_count (self ):
286- return get_status_log_count ()
294+ return get_status_log_count (self . _handle )
287295
288296 def get_status_log_for_retention_time (self , rt ):
289297 from .data .classes import LogEntry
290298 labels = [h .label for h in self .get_status_log_header_information ()]
291- return LogEntry (get_status_log_values_for_rt (rt ), labels )
299+ return LogEntry (get_status_log_values_for_rt (self . _handle , rt ), labels )
292300 def get_tune_data_count (self ):
293- return get_tune_data_count ()
301+ return get_tune_data_count (self . _handle )
294302 def get_tune_data (self , index ): return None
295- def get_filters (self ): return get_filters ()
303+ def get_filters (self ): return get_filters (self . _handle )
296304 def get_auto_filters (self ): return []
297305 def get_filter_for_scan_number (self , scan_number ):
298306 from .data .classes import ScanFilter
@@ -302,7 +310,7 @@ def get_scan_dependents(self, scan_number, precision): return ScanDependents()
302310
303311 @property
304312 def has_ms_data (self ) -> bool :
305- return has_ms_data ()
313+ return has_ms_data (self . _handle )
306314
307315 def get_scan_type (self , scan_number : int ):
308316 return ""
@@ -324,32 +332,32 @@ def instrument_methods_count(self) -> int:
324332
325333 @property
326334 def instrument_count (self ) -> int :
327- return get_instrument_count ()
335+ return get_instrument_count (self . _handle )
328336
329337 @property
330338 def total_time_min (self ) -> float :
331- return get_end_time ()
339+ return get_end_time (self . _handle )
332340
333341 def get_chromatogram (self , mass : float = 0.0 , tolerance : float = 0.0 , trace_type : int = 1 , ms_filter : str = 'ms' ) -> Tuple [np .ndarray , np .ndarray ]:
334342 starts = [mass - tolerance ] if mass > 0 else []
335343 ends = [mass + tolerance ] if mass > 0 else []
336- times , intensities = get_chromatogram (int (trace_type ), ms_filter , starts , ends , - 1 , - 1 , 1000000 )
344+ times , intensities = get_chromatogram (self . _handle , int (trace_type ), ms_filter , starts , ends , - 1 , - 1 , 1000000 )
337345 return np .array (times ), np .array (intensities )
338346
339347 def get_averaged_ms2_scans (self , scan_numbers : List [int ]) -> Tuple [np .ndarray , np .ndarray , int ]:
340348 if not scan_numbers :
341349 return np .array ([]), np .array ([]), 0
342- masses , intensities = get_averaged_spectrum (scan_numbers , 1000000 )
350+ masses , intensities = get_averaged_spectrum (self . _handle , scan_numbers , 1000000 )
343351 return np .array (masses ), np .array (intensities ), scan_numbers [0 ]
344352
345353 def get_ms1_scan_number_from_retention_time (self , rt : float ) -> Tuple [int , float ]:
346- scan_number = get_ms1_scan_number_from_rt (rt )
354+ scan_number = get_ms1_scan_number_from_rt (self . _handle , rt )
347355 if scan_number < 1 : return 0 , 0.0
348356 return scan_number , self .retention_time_from_scan_number (scan_number )
349357
350358 def get_ms2_scan_number_from_retention_time (self , rt : float , precursor_mz : float = None ) -> Tuple [int , float ]:
351359 pmz = precursor_mz if precursor_mz is not None else 0.0
352- scan_number = get_ms2_scan_number_from_rt (rt , pmz , 1.0 )
360+ scan_number = get_ms2_scan_number_from_rt (self . _handle , rt , pmz , 1.0 )
353361 if scan_number < 1 : return 0 , 0.0
354362 return scan_number , self .retention_time_from_scan_number (scan_number )
355363
@@ -384,23 +392,23 @@ def ms2_filter_masses(self) -> List[float]:
384392 if not hasattr (self , "_ms2_filter_masses_cache" ):
385393 mass_set = set ()
386394 for i in range (self .first_scan , self .last_scan + 1 ):
387- if get_ms_order (i ) == 2 :
388- mass_set .add (get_precursor_mass (i ))
395+ if get_ms_order (self . _handle , i ) == 2 :
396+ mass_set .add (get_precursor_mass (self . _handle , i ))
389397 self ._ms2_filter_masses_cache = sorted (list (mass_set ))
390398 return self ._ms2_filter_masses_cache
391399
392400 def get_precursor_mz (self , scan_number : int ) -> float :
393- return get_precursor_mass (scan_number )
401+ return get_precursor_mass (self . _handle , scan_number )
394402
395403 def get_scan_from_scan_number (self , scan_number : int ):
396404 # Use get_centroid_stream to match behavior for parity
397- masses , intensities , * _ = get_centroid_stream (scan_number , 1000000 )
405+ masses , intensities , * _ = get_centroid_stream (self . _handle , scan_number , 1000000 )
398406 charges = np .zeros_like (masses )
399407 event_str = self .get_scan_event_string_for_scan_number (scan_number )
400408 return np .array (masses ), np .array (intensities ), charges , event_str
401409
402410 def get_scan_number_from_retention_time (self , rt : float ) -> int :
403- return get_scan_number_from_rt (rt )
411+ return get_scan_number_from_rt (self . _handle , rt )
404412
405413 def __enter__ (self ):
406414 return self
@@ -409,4 +417,6 @@ def __exit__(self, exc_type, exc_val, exc_tb):
409417 self .close ()
410418
411419 def close (self ):
412- close_raw_file ()
420+ if hasattr (self , "_handle" ) and self ._handle > 0 :
421+ close_raw_file (self ._handle )
422+ self ._handle = - 1
0 commit comments