seabirdfilehandler 0.5.3__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of seabirdfilehandler might be problematic. Click here for more details.

@@ -3,6 +3,8 @@ from .bottlefile import *
3
3
  from .bottlelogfile import *
4
4
  from .cnvfile import *
5
5
  from .xmlfiles import *
6
+ from .hexfile import *
6
7
  from .validation_modules import *
7
- from .file_collection import *
8
8
  from .geomar_ctd_file_parser import *
9
+ from .parameter import *
10
+ from .file_collection import *
@@ -1,3 +1,4 @@
1
+ from pathlib import Path
1
2
  from typing import Union
2
3
  from datetime import datetime, time
3
4
  import pandas as pd
@@ -22,12 +23,13 @@ class BottleFile(DataFile):
22
23
 
23
24
  """
24
25
 
25
- def __init__(self, path_to_file):
26
- super().__init__(path_to_file)
27
- self.original_df = self.create_dataframe()
28
- self.df = self.original_df
29
- self.setting_dataframe_dtypes()
30
- self.adding_timestamp_column()
26
+ def __init__(self, path_to_file: Path | str, only_header: bool = False):
27
+ super().__init__(path_to_file, only_header)
28
+ if not only_header:
29
+ self.original_df = self.create_dataframe()
30
+ self.df = self.original_df
31
+ self.setting_dataframe_dtypes()
32
+ self.adding_timestamp_column()
31
33
 
32
34
  def create_dataframe(self):
33
35
  """Creates a dataframe out of the btl file. Manages the double data
@@ -60,9 +60,11 @@ class CnvFile(DataFile):
60
60
  super().__init__(path_to_file, only_header)
61
61
  self.validation_modules = self.obtaining_validation_modules()
62
62
  self.start_time = self.reading_start_time()
63
- self.parameters = Parameters(self.data, self.data_table_description)
63
+ self.parameters = Parameters(
64
+ self.data, self.data_table_description, only_header
65
+ )
64
66
  if create_dataframe:
65
- self.df = self.parameters.get_pandas_dataframe()
67
+ self.df = self.create_dataframe()
66
68
  if absolute_time_calculation:
67
69
  self.absolute_time_calculation()
68
70
  if event_log_column:
@@ -70,6 +72,13 @@ class CnvFile(DataFile):
70
72
  if coordinate_columns:
71
73
  self.add_position_columns()
72
74
 
75
+ def create_dataframe(self) -> pd.DataFrame:
76
+ """
77
+ Plain dataframe creator.
78
+ """
79
+ self.df = self.parameters.get_pandas_dataframe()
80
+ return self.df
81
+
73
82
  def reading_start_time(
74
83
  self,
75
84
  time_source: str = "System UTC",
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  from pathlib import Path
2
3
  import logging
3
4
  from collections import UserList
@@ -8,25 +9,77 @@ from seabirdfilehandler import (
8
9
  CnvFile,
9
10
  BottleFile,
10
11
  BottleLogFile,
12
+ DataFile,
13
+ HexFile,
11
14
  )
12
- from seabirdfilehandler import DataFile
13
15
  from seabirdfilehandler.utils import get_unique_sensor_data
14
16
 
15
17
  logger = logging.getLogger(__name__)
16
18
 
17
19
 
20
+ def get_collection(
21
+ path_to_files: Path | str,
22
+ file_suffix: str = "cnv",
23
+ only_metadata: bool = False,
24
+ pattern: str = "",
25
+ sorting_key: Callable | None = None,
26
+ ) -> Type[FileCollection]:
27
+ """
28
+ Factory to create instances of FileCollection, depending on input type.
29
+
30
+ Parameters
31
+ ----------
32
+ path_to_files : Path | str :
33
+ The path to the directory to search for files.
34
+ file_suffix : str :
35
+ The suffix to search for. (Default value = "cnv")
36
+ only_metadata : bool :
37
+ Whether to read only metadata. (Default value = False)
38
+ pattern: str
39
+ A filter for file selection. (Default value = '')
40
+ sorting_key : Callable | None :
41
+ A callable that returns the filename-part to use to sort the collection. (Default value = None)
42
+ Returns
43
+ -------
44
+ An instance of FileCollection or one of its children.
45
+
46
+ """
47
+ mapping_suffix_to_type = {
48
+ "cnv": CnvCollection,
49
+ "btl": FileCollection,
50
+ "bl": FileCollection,
51
+ "hex": HexCollection,
52
+ }
53
+ file_suffix = file_suffix.strip(".")
54
+ try:
55
+ collection = mapping_suffix_to_type[file_suffix](
56
+ path_to_files, file_suffix, only_metadata, pattern, sorting_key
57
+ )
58
+ except KeyError:
59
+ raise ValueError(f"Unknown input file type: {file_suffix}, aborting.")
60
+ else:
61
+ return collection
62
+
63
+
18
64
  class FileCollection(UserList):
19
- """A representation of multiple files of the same kind. These files share
65
+ """
66
+ A representation of multiple files of the same kind. These files share
20
67
  the same suffix and are otherwise closely connected to each other. A common
21
68
  use case would be the collection of CNVs to allow for easier processing or
22
69
  integration of field calibration measurements.
23
70
 
24
71
  Parameters
25
72
  ----------
26
-
27
- Returns
28
- -------
29
-
73
+ path_to_files : Path | str :
74
+ The path to the directory to search for files.
75
+ file_suffix : str :
76
+ The suffix to search for. (Default value = "cnv")
77
+ only_metadata : bool :
78
+ Whether to read only metadata. (Default value = False)
79
+ pattern: str
80
+ A filter for file selection. (Default value = '')
81
+ sorting_key : Callable | None :
82
+ A callable that returns the filename-part to use to sort the collection. (Default value = None)
30
83
  """
31
84
 
32
85
  def __init__(
@@ -34,66 +87,108 @@ class FileCollection(UserList):
34
87
  path_to_files: str | Path,
35
88
  file_suffix: str,
36
89
  only_metadata: bool = False,
90
+ pattern: str = "",
37
91
  sorting_key: Callable | None = None,
38
92
  ):
39
93
  super().__init__()
40
94
  self.path_to_files = Path(path_to_files)
41
95
  self.file_suffix = file_suffix.strip(".")
42
- self.file_type: Type[DataFile]
43
- self.extract_file_type()
44
- self.individual_file_paths = []
45
- self.collect_files(sorting_key=sorting_key)
46
- self.load_files(only_metadata)
96
+ self.pattern = pattern
97
+ self.sorting_key = sorting_key
98
+ self.file_type = self.extract_file_type(self.file_suffix)
99
+ self.individual_file_paths = self.collect_files(
100
+ pattern=pattern,
101
+ sorting_key=sorting_key,
102
+ )
103
+ self.data = self.load_files(only_metadata)
47
104
  if not only_metadata:
48
- if self.file_type == DataFile:
49
- self.df_list = self.get_dataframes()
50
- self.df = self.get_collection_dataframe(self.df_list)
51
- if self.file_type == CnvFile:
52
- self.data_meta_info = self.get_data_table_meta_info()
53
- self.sensor_data = get_unique_sensor_data(
54
- [file.sensors for file in self.data]
55
- )
105
+ self.df_list = self.get_dataframes()
106
+ self.df = self.get_collection_dataframe(self.df_list)
56
107
 
57
108
  def __str__(self):
58
109
  return "/n".join(self.data)
59
110
 
60
- def extract_file_type(self):
61
- """ """
111
+ def extract_file_type(self, suffix: str) -> Type[DataFile]:
112
+ """
113
+ Determines the file type using the input suffix.
114
+
115
+ Parameters
116
+ ----------
117
+ suffix : str :
118
+ The file suffix.
119
+ Returns
120
+ -------
121
+ An object corresponding to the given suffix.
122
+ """
62
123
  mapping_suffix_to_type = {
63
124
  "cnv": CnvFile,
64
125
  "btl": BottleFile,
65
126
  "bl": BottleLogFile,
127
+ "hex": HexFile,
66
128
  }
129
+ file_type = DataFile
67
130
  for key, value in mapping_suffix_to_type.items():
68
- if key == self.file_suffix:
69
- self.file_type = value
131
+ if key == suffix:
132
+ file_type = value
70
133
  break
71
- else:
72
- self.file_type = DataFile
134
+ return file_type
73
135
 
74
136
  def collect_files(
75
137
  self,
138
+ pattern: str = "",
76
139
  sorting_key: Callable | None = lambda file: int(
77
140
  file.stem.split("_")[3]
78
141
  ),
79
- ):
80
- """ """
81
- self.individual_file_paths = sorted(
82
- self.path_to_files.rglob(f"*{self.file_suffix}"),
142
+ ) -> list[Path]:
143
+ """
144
+ Creates a list of target files, recursively from the given directory.
145
+ These can be sorted with the help of the sorting_key parameter, which
146
+ is a Callable that identifies the part of the filename that shall be
147
+ used for sorting.
148
+
149
+ Parameters
150
+ ----------
151
+ pattern: str
152
+ A filter for file selection. Is given to rglob. (Default value = '')
153
+ sorting_key : Callable | None :
154
+ The part of the filename to use in sorting. (Default value = lambda file: int(file.stem.split("_")[3]))
155
+ Returns
156
+ -------
157
+ A list of all paths found.
158
+ """
159
+ return sorted(
160
+ self.path_to_files.rglob(f"*{pattern}*{self.file_suffix}"),
83
161
  key=sorting_key,
84
162
  )
85
163
 
86
- def load_files(self, only_metadata: bool = False):
87
- """ """
164
+ def load_files(self, only_metadata: bool = False) -> list[DataFile]:
165
+ """
166
+ Creates python instances of each file.
167
+
168
+ Parameters
169
+ ----------
170
+ only_metadata : bool :
171
+ Whether to load only file metadata. (Default value = False)
172
+ Returns
173
+ -------
174
+ A list of all instances.
175
+ """
176
+ data = []
88
177
  for file in self.individual_file_paths:
89
178
  try:
90
- self.data.append(self.file_type(file))
179
+ data.append(
180
+ self.file_type(
181
+ path_to_file=file,
182
+ only_header=only_metadata,
183
+ )
184
+ )
91
185
  except TypeError:
92
186
  logger.error(
93
187
  f"Could not open file {file} with the type "
94
188
  f"{self.file_type}."
95
189
  )
96
190
  continue
191
+ return data
97
192
 
98
193
  def get_dataframes(
99
194
  self,
@@ -101,35 +196,27 @@ class FileCollection(UserList):
101
196
  coordinates: bool = False,
102
197
  time_correction: bool = False,
103
198
  cast_identifier: bool = False,
104
- long_header_names: bool = False,
105
- full_data_header: bool = True,
106
199
  ) -> list[pd.DataFrame]:
107
200
  """
201
+ Collects all individual dataframes and allows additional column
202
+ creation.
108
203
 
109
204
  Parameters
110
205
  ----------
111
- event_log: bool :
112
- (Default value = False)
113
- coordinates: bool :
114
- (Default value = False)
115
- time_correction: bool :
116
- (Default value = False)
117
- cast_identifier: bool :
118
- (Default value = False)
119
- long_header_names: bool :
120
- (Default value = False)
121
- full_data_header: bool :
122
- (Default value = True)
206
+ event_log : bool :
207
+ (Default value = False)
208
+ coordinates : bool :
209
+ (Default value = False)
210
+ time_correction : bool :
211
+ (Default value = False)
212
+ cast_identifier : bool :
213
+ (Default value = False)
123
214
 
124
215
  Returns
125
216
  -------
126
-
217
+ A list of the individual pandas DataFrames.
127
218
  """
128
219
  for index, file in enumerate(self.data):
129
- if full_data_header:
130
- file.rename_dataframe_header(header_detail_level="longinfo")
131
- elif long_header_names:
132
- file.rename_dataframe_header(header_detail_level="name")
133
220
  if event_log:
134
221
  file.add_station_and_event_column()
135
222
  if coordinates:
@@ -145,33 +232,35 @@ class FileCollection(UserList):
145
232
  self, list_of_dfs: list[pd.DataFrame] | None = None
146
233
  ) -> pd.DataFrame:
147
234
  """
235
+ Creates one DataFrame from the individual ones, by concatenation.
148
236
 
149
237
  Parameters
150
238
  ----------
151
- list_of_dfs: list[pd.DataFrame] | None :
152
- (Default value = None)
153
-
239
+ list_of_dfs : list[pd.DataFrame] | None :
240
+ A list of the individual DataFrames. (Default value = None)
154
241
  Returns
155
242
  -------
156
-
243
+ A pandas DataFrame representing the whole dataset.
157
244
  """
158
245
  if not list_of_dfs:
159
246
  list_of_dfs = self.get_dataframes()
247
+ if not list_of_dfs:
248
+ raise ValueError("No dataframes to concatenate.")
160
249
  df = pd.concat(list_of_dfs, ignore_index=True)
161
- # df.meta.metadata = list_of_dfs[0].meta.metadata
250
+ self.df = df
162
251
  return df
163
252
 
164
253
  def tidy_collection_dataframe(self, df: pd.DataFrame) -> pd.DataFrame:
165
254
  """
255
+ Apply the different dataframe edits to the given dataframe.
166
256
 
167
257
  Parameters
168
258
  ----------
169
- df: pd.DataFrame :
170
-
171
-
259
+ df : pd.DataFrame :
260
+ A DataFrame to edit.
172
261
  Returns
173
262
  -------
174
-
263
+ The tidied dataframe.
175
264
  """
176
265
  df = self.use_bad_flag_for_nan(df)
177
266
  df = self.set_dtype_to_float(df)
@@ -179,15 +268,15 @@ class FileCollection(UserList):
179
268
 
180
269
  def use_bad_flag_for_nan(self, df: pd.DataFrame) -> pd.DataFrame:
181
270
  """
271
+ Replace all Nan values by the bad flag value, defined inside the files.
182
272
 
183
273
  Parameters
184
274
  ----------
185
- df: pd.DataFrame :
186
-
187
-
275
+ df : pd.DataFrame :
276
+ The dataframe to edit.
188
277
  Returns
189
278
  -------
190
-
279
+ The edited DataFrame.
191
280
  """
192
281
  bad_flags = set()
193
282
  for file in self.data:
@@ -201,15 +290,15 @@ class FileCollection(UserList):
201
290
 
202
291
  def set_dtype_to_float(self, df: pd.DataFrame) -> pd.DataFrame:
203
292
  """
293
+ Use the float-dtype for all DataFrame columns.
204
294
 
205
295
  Parameters
206
296
  ----------
207
- df: pd.DataFrame :
208
-
209
-
297
+ df : pd.DataFrame :
298
+ The dataframe to edit.
210
299
  Returns
211
300
  -------
212
-
301
+ The edited DataFrame.
213
302
  """
214
303
  for parameter in df.columns:
215
304
  if parameter in ["datetime"]:
@@ -222,37 +311,182 @@ class FileCollection(UserList):
222
311
 
223
312
  def select_real_scan_data(self, df: pd.DataFrame) -> pd.DataFrame:
224
313
  """
314
+ Drop data rows have no 'Scan' value, if that column exists.
225
315
 
226
316
  Parameters
227
317
  ----------
228
- df: pd.DataFrame :
229
-
230
-
318
+ df : pd.DataFrame :
319
+ The dataframe to edit.
231
320
  Returns
232
321
  -------
233
-
322
+ The edited DataFrame.
234
323
  """
235
- # TODO: fix this hardcoded name
236
324
  try:
237
- df = df.loc[df["Scan Count"].notna()]
238
- finally:
239
- pass
325
+ scan_column = [
326
+ c for c in df.columns if c.lower().startswith("scan")
327
+ ][0]
328
+ except IndexError:
329
+ return df
330
+ else:
331
+ df = df.loc[df[scan_column].notna()]
240
332
  return df
241
333
 
242
334
  def to_csv(self, file_name):
243
335
  """
336
+ Writes a csv file with the given filename.
244
337
 
245
338
  Parameters
246
339
  ----------
247
340
  file_name :
341
+ The new csv file name.
342
+ """
343
+ self.df.to_csv(file_name)
344
+
345
+
346
+ class CnvCollection(FileCollection):
347
+ """
348
+ Specific methods to work with collections of .cnv files.
349
+ """
350
+
351
+ def __init__(
352
+ self,
353
+ *args,
354
+ **kwargs,
355
+ ):
356
+ super().__init__(*args, **kwargs)
357
+ self.data_meta_info = self.get_data_table_meta_info()
358
+ self.sensor_data = get_unique_sensor_data(
359
+ [file.sensors for file in self.data]
360
+ )
361
+ self.array = self.get_array()
248
362
 
363
+ def get_dataframes(
364
+ self,
365
+ event_log: bool = False,
366
+ coordinates: bool = False,
367
+ time_correction: bool = False,
368
+ cast_identifier: bool = False,
369
+ ) -> list[pd.DataFrame]:
370
+ """
371
+ Collects all individual dataframes and allows additional column
372
+ creation.
249
373
 
374
+ Parameters
375
+ ----------
376
+ event_log : bool :
377
+ (Default value = False)
378
+ coordinates : bool :
379
+ (Default value = False)
380
+ time_correction : bool :
381
+ (Default value = False)
382
+ cast_identifier : bool :
383
+ (Default value = False)
250
384
  Returns
251
385
  -------
386
+ A list of the individual pandas DataFrames.
387
+ """
388
+ for index, file in enumerate(self.data):
389
+ if event_log:
390
+ file.add_station_and_event_column()
391
+ if coordinates:
392
+ file.add_position_columns()
393
+ if time_correction:
394
+ file.absolute_time_calculation()
395
+ file.add_start_time()
396
+ if cast_identifier:
397
+ file.add_cast_number(index + 1)
398
+ return [file.create_dataframe() for file in self.data]
252
399
 
400
+ def get_data_table_meta_info(self) -> list[dict]:
253
401
  """
254
- self.get_collection_dataframe().to_csv(file_name)
402
+ Ensures the same data description in all input cnv files and returns
403
+ it.
404
+ Acts as an early alarm when working on different kinds of files, which
405
+ cannot be concatenated together.
255
406
 
256
- def get_data_table_meta_info(self) -> list[list[dict]]:
257
- """ """
258
- return [file.parameters.metadata for file in self.data]
407
+ Returns
408
+ -------
409
+ A list of dictionaries that represent the data column information.
410
+ """
411
+ all_column_descriptions = [
412
+ file.parameters.metadata for file in self.data
413
+ ]
414
+ for info in all_column_descriptions:
415
+ if all_column_descriptions[0] != info:
416
+ raise AssertionError(
417
+ "Acting on differently formed data files, aborting"
418
+ )
419
+ return all_column_descriptions[0]
420
+
421
+ def get_array(self) -> np.ndarray:
422
+ """
423
+ Creates a collection array of all individual file arrays.
424
+
425
+ Returns
426
+ -------
427
+ A numpy array, representing the data of all input files.
428
+ """
429
+ return np.concatenate(
430
+ [file.parameters.create_full_ndarray() for file in self.data]
431
+ )
432
+
433
+
434
+ class HexCollection(FileCollection):
435
+ """
436
+ Specific methods to work with collections of .hex files.
437
+
438
+ Especially concerned with the detection of corresponding .XMLCON files.
439
+ """
440
+
441
+ def __init__(
442
+ self,
443
+ *args,
444
+ xmlcon_pattern: str = "",
445
+ path_to_xmlcons: Path | str = "",
446
+ **kwargs,
447
+ ):
448
+ # force only_metadata, as the hex data cannot be put into a DataFrame
449
+ kwargs["only_metadata"] = True
450
+ super().__init__(*args, **kwargs)
451
+ if not xmlcon_pattern:
452
+ xmlcon_pattern = self.pattern
453
+ self.xmlcon_pattern = xmlcon_pattern
454
+ self.path_to_xmlcons = (
455
+ Path(path_to_xmlcons)
456
+ if path_to_xmlcons
457
+ else self.path_to_files.parent
458
+ )
459
+ self.xmlcons = self.get_xmlcons()
460
+
461
+ def get_xmlcons(self) -> list[str]:
462
+ """
463
+ Returns all .xmlcon files found inside the root directory and its
464
+ children, matching a given pattern.
465
+
466
+ Does use the global sorting_key to attempt to also sort the xmlcons the
467
+ same way.
468
+ This is meant to be used in the future for a more specific hex-xmlcon
469
+ matching.
470
+
471
+ Returns
472
+ -------
473
+ A list of the found xmlcon filenames.
474
+ """
475
+ try:
476
+ xmlcons = [
477
+ Path(xmlcon_path).stem
478
+ for xmlcon_path in sorted(
479
+ self.path_to_xmlcons.rglob(
480
+ f"*{self.xmlcon_pattern}*.XMLCON"
481
+ ),
482
+ key=self.sorting_key,
483
+ )
484
+ ]
485
+ except (KeyError, IndexError):
486
+ xmlcons = [
487
+ Path(xmlcon_path).stem
488
+ for xmlcon_path in self.path_to_xmlcons.rglob(
489
+ f"*{self.xmlcon_pattern}*.XMLCON"
490
+ )
491
+ ]
492
+ return xmlcons
@@ -0,0 +1,71 @@
1
+ from pathlib import Path
2
+ from seabirdfilehandler import DataFile, XMLCONFile
3
+
4
+
5
+ class HexFile(DataFile):
6
+ """
7
+ A representation of a .hex file as used by SeaBird.
8
+
9
+ Parameters
10
+ ----------
11
+ path_to_file: Path | str:
12
+ the path to the file
13
+ """
14
+
15
+ def __init__(
16
+ self,
17
+ path_to_file: Path | str,
18
+ path_to_xmlcon: Path | str = "",
19
+ *args,
20
+ **kwargs,
21
+ ):
22
+ # force loading only metadata
23
+ super().__init__(path_to_file, True)
24
+ self.xmlcon = self.get_corresponding_xmlcon(path_to_xmlcon)
25
+
26
+ def get_corresponding_xmlcon(
27
+ self,
28
+ path_to_xmlcon: Path | str = "",
29
+ ) -> XMLCONFile | None:
30
+ """
31
+ Finds the best matching .xmlcon file inside the same directory.
32
+
33
+ Parameters
34
+ ----------
35
+ path_to_xmlcon: Path | str:
36
+ A fixed path to a xmlcon file. Will be checked.
37
+ """
38
+ # xmlcon path given, test and use it
39
+ if isinstance(path_to_xmlcon, str):
40
+ if path_to_xmlcon:
41
+ return XMLCONFile(path_to_xmlcon)
42
+ else:
43
+ if path_to_xmlcon.exists():
44
+ return XMLCONFile(path_to_xmlcon)
45
+ # no xmlcon path, lets find one in the same dir
46
+ # get all xmlcons in the dir
47
+ xmlcons = [
48
+ xmlcon.stem
49
+ for xmlcon in self.file_dir.glob("*.XMLCON", case_sensitive=False)
50
+ ]
51
+ if not xmlcons:
52
+ return None
53
+ # find excact match
54
+ if self.file_name in xmlcons:
55
+ return XMLCONFile(
56
+ self.file_dir.joinpath(self.file_name + ".XMLCON")
57
+ )
58
+ # TODO:
59
+ # otherwise, take the last fitting one in a sorted xmlcon list, or,
60
+ # the one sharing the same prefix
61
+ else:
62
+ same_prefix_xmlcons = [
63
+ xmlcon
64
+ for xmlcon in xmlcons
65
+ if self.file_name.startswith(xmlcon[:5])
66
+ ]
67
+ if not same_prefix_xmlcons:
68
+ return None
69
+ return XMLCONFile(
70
+ self.file_dir.joinpath(same_prefix_xmlcons[0] + ".XMLCON")
71
+ )
@@ -32,15 +32,17 @@ class Parameters(UserDict):
32
32
  self,
33
33
  data: list,
34
34
  metadata: list,
35
+ only_header: bool = False,
35
36
  ):
36
37
  self.raw_input_data = data
37
38
  self.raw_metadata = metadata
38
- self.full_data_array = self.create_full_ndarray()
39
39
  self.differentiate_table_description()
40
40
  self.metadata, self.duplicate_columns = self.reading_data_header(
41
41
  metadata
42
42
  )
43
- self.data = self.create_parameter_instances()
43
+ if not only_header:
44
+ self.full_data_array = self.create_full_ndarray()
45
+ self.data = self.create_parameter_instances()
44
46
 
45
47
  def get_parameter_names(self) -> list[str]:
46
48
  return [parameter["name"] for parameter in self.metadata.values()]
@@ -33,6 +33,23 @@ class XMLFile(UserDict):
33
33
  self.xml_tree = ET.fromstring(self.input)
34
34
  self.data = xmltodict.parse(self.input)
35
35
 
36
+ def __eq__(self, other) -> bool:
37
+ """
38
+ Allows comparison of two instances of this class.
39
+
40
+ Uses the parsed xml information to determine equality.
41
+
42
+ Parameters
43
+ ----------
44
+ other: XMLFile
45
+ An instance of this class.
46
+
47
+ Returns
48
+ -------
49
+ Whether the given instance and this one are equal.
50
+ """
51
+ return self.data == other.data
52
+
36
53
  def to_xml(self, file_name=None, file_path=None):
37
54
  """
38
55
  Writes the dictionary to xml.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: seabirdfilehandler
3
- Version: 0.5.3
3
+ Version: 0.6.0
4
4
  Summary: Library of parsers to interact with SeaBird CTD files.
5
5
  Keywords: CTD,parser,seabird,data
6
6
  Author: Emil Michels
@@ -16,7 +16,8 @@ Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
17
  Requires-Dist: pandas (>=2.2.1)
18
18
  Requires-Dist: xmltodict (>=0.13.0)
19
- Project-URL: Homepage, https://git.io-warnemuende.de/CTD-Software/SeabirdFileHandler
19
+ Project-URL: Documentation, https://ctd-software.pages.io-warnemuende.de/seabirdfilehandler
20
+ Project-URL: Homepage, https://ctd-software.pages.io-warnemuende.de/seabirdfilehandler
20
21
  Project-URL: Repository, https://git.io-warnemuende.de/CTD-Software/SeabirdFileHandler
21
22
  Description-Content-Type: text/markdown
22
23
 
@@ -0,0 +1,16 @@
1
+ seabirdfilehandler/__init__.py,sha256=XMmhfwZ3YPzR3sLTi8AHN6mSlrQA1tLEpw02_fI7Rr0,278
2
+ seabirdfilehandler/bottlefile.py,sha256=qCh506J3MWZXM11243aw_oJRocVB0ZIipXQLEgkD5M0,6046
3
+ seabirdfilehandler/bottlelogfile.py,sha256=MtMmEebdAktO3mk6KbmJC7dfx9sRLbV5qqDQt2qtpJE,4310
4
+ seabirdfilehandler/cnvfile.py,sha256=j7IR3EgCrGD3riKOzFSKFNW6lkuzZYGYkxI_czcD8XU,10196
5
+ seabirdfilehandler/datafiles.py,sha256=9r0Mh3zPYJJ3CoybgOBH4Dsq43kLDnca9m8s_V0cYU8,9378
6
+ seabirdfilehandler/file_collection.py,sha256=8uLoN55h00_EmiEa4mbyaSJZst7w8NhODv7DrtzEAwc,15021
7
+ seabirdfilehandler/geomar_ctd_file_parser.py,sha256=4eCnkE0mvPKC8Dic8sXP4xpfwnk3K2MQcGFBf6loT8k,2655
8
+ seabirdfilehandler/hexfile.py,sha256=TBplwbWHrTuJzv2qlx6xYNtoX43I2YUabDmaGZuBEDQ,2144
9
+ seabirdfilehandler/parameter.py,sha256=CjC8T5wfbThryqVNjTcAolug9gi_BnInfZzkEfmKm5E,14561
10
+ seabirdfilehandler/utils.py,sha256=5KXdB8Hdv65dv5tPyXxNMct1mCEOyA3S8XP54AFAnx0,1745
11
+ seabirdfilehandler/validation_modules.py,sha256=eZ6x0giftUtlxnRMOnK_vCkgccdwUXPrDjajFa-E6n0,4698
12
+ seabirdfilehandler/xmlfiles.py,sha256=XqqbVNjyINySoe2ZC_qJglkAqshavZxT2-jorDOSj7Y,5084
13
+ seabirdfilehandler-0.6.0.dist-info/LICENSE,sha256=Ifd1VPmYv32oJd2QVh3wIQP9X05vYJlcY6kONz360ws,34603
14
+ seabirdfilehandler-0.6.0.dist-info/METADATA,sha256=-HcIPCv4_SMttVtN0kXdr-UKJy5iUsFx0Onde2YXQwE,2307
15
+ seabirdfilehandler-0.6.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
16
+ seabirdfilehandler-0.6.0.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- seabirdfilehandler/__init__.py,sha256=rS1NfxKVWgOntk5NL-ndZyDt3LHW_tKr_F3iW_QbYvg,230
2
- seabirdfilehandler/bottlefile.py,sha256=nnfoDczPMG_ge40dT2rHNhifR7-NRgnZNFrfPM_9OSQ,5925
3
- seabirdfilehandler/bottlelogfile.py,sha256=MtMmEebdAktO3mk6KbmJC7dfx9sRLbV5qqDQt2qtpJE,4310
4
- seabirdfilehandler/cnvfile.py,sha256=0fDovJ6WJsxkbtonbuKIPDY2E5Ex1k-1WD5nkA2WRyg,9990
5
- seabirdfilehandler/datafiles.py,sha256=9r0Mh3zPYJJ3CoybgOBH4Dsq43kLDnca9m8s_V0cYU8,9378
6
- seabirdfilehandler/file_collection.py,sha256=b5iJaP4F34Vq7-FiJOlPvfS4IePGWsYx20XwWbZQw1A,6882
7
- seabirdfilehandler/geomar_ctd_file_parser.py,sha256=4eCnkE0mvPKC8Dic8sXP4xpfwnk3K2MQcGFBf6loT8k,2655
8
- seabirdfilehandler/parameter.py,sha256=wBBSe85-Eqc3YmntuZmwvny1l2exXATri-oak8xEKX0,14490
9
- seabirdfilehandler/utils.py,sha256=5KXdB8Hdv65dv5tPyXxNMct1mCEOyA3S8XP54AFAnx0,1745
10
- seabirdfilehandler/validation_modules.py,sha256=eZ6x0giftUtlxnRMOnK_vCkgccdwUXPrDjajFa-E6n0,4698
11
- seabirdfilehandler/xmlfiles.py,sha256=L_puQf8eg0ojv85AyEMID4jnwkOlV_fgZP3W5yeSUBY,4668
12
- seabirdfilehandler-0.5.3.dist-info/LICENSE,sha256=Ifd1VPmYv32oJd2QVh3wIQP9X05vYJlcY6kONz360ws,34603
13
- seabirdfilehandler-0.5.3.dist-info/METADATA,sha256=7LNvhfKbt5_sjuLNhqO8t1h2iKKZyS7sJZhT0nh2c4w,2213
14
- seabirdfilehandler-0.5.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
15
- seabirdfilehandler-0.5.3.dist-info/RECORD,,