masster 0.4.13__tar.gz → 0.4.14__tar.gz

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 masster might be problematic. Click here for more details.

Files changed (88) hide show
  1. {masster-0.4.13 → masster-0.4.14}/PKG-INFO +1 -1
  2. {masster-0.4.13 → masster-0.4.14}/pyproject.toml +1 -1
  3. {masster-0.4.13 → masster-0.4.14}/src/masster/_version.py +1 -1
  4. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/sample.py +41 -0
  5. {masster-0.4.13 → masster-0.4.14}/src/masster/study/processing.py +79 -51
  6. {masster-0.4.13 → masster-0.4.14}/src/masster/study/study.py +61 -0
  7. {masster-0.4.13 → masster-0.4.14}/uv.lock +1 -1
  8. {masster-0.4.13 → masster-0.4.14}/.github/workflows/publish.yml +0 -0
  9. {masster-0.4.13 → masster-0.4.14}/.github/workflows/security.yml +0 -0
  10. {masster-0.4.13 → masster-0.4.14}/.github/workflows/test.yml +0 -0
  11. {masster-0.4.13 → masster-0.4.14}/.gitignore +0 -0
  12. {masster-0.4.13 → masster-0.4.14}/.pre-commit-config.yaml +0 -0
  13. {masster-0.4.13 → masster-0.4.14}/LICENSE +0 -0
  14. {masster-0.4.13 → masster-0.4.14}/Makefile +0 -0
  15. {masster-0.4.13 → masster-0.4.14}/README.md +0 -0
  16. {masster-0.4.13 → masster-0.4.14}/TESTING.md +0 -0
  17. {masster-0.4.13 → masster-0.4.14}/demo/example_batch_process.py +0 -0
  18. {masster-0.4.13 → masster-0.4.14}/demo/example_sample_process.py +0 -0
  19. {masster-0.4.13 → masster-0.4.14}/src/masster/__init__.py +0 -0
  20. {masster-0.4.13 → masster-0.4.14}/src/masster/chromatogram.py +0 -0
  21. {masster-0.4.13 → masster-0.4.14}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_DDA_OT_C-MiLUT_QC_dil2_01_20250602151849.sample5 +0 -0
  22. {masster-0.4.13 → masster-0.4.14}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_DDA_OT_C-MiLUT_QC_dil3_01_20250602150634.sample5 +0 -0
  23. {masster-0.4.13 → masster-0.4.14}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_MS1_C-MiLUT_C008_v6_r38_01.sample5 +0 -0
  24. {masster-0.4.13 → masster-0.4.14}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_MS1_C-MiLUT_C008_v7_r37_01.sample5 +0 -0
  25. {masster-0.4.13 → masster-0.4.14}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_MS1_C-MiLUT_C017_v5_r99_01.sample5 +0 -0
  26. {masster-0.4.13 → masster-0.4.14}/src/masster/data/libs/ccm.csv +0 -0
  27. {masster-0.4.13 → masster-0.4.14}/src/masster/data/libs/urine.csv +0 -0
  28. {masster-0.4.13 → masster-0.4.14}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.timeseries.data +0 -0
  29. {masster-0.4.13 → masster-0.4.14}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff +0 -0
  30. {masster-0.4.13 → masster-0.4.14}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff.scan +0 -0
  31. {masster-0.4.13 → masster-0.4.14}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff2 +0 -0
  32. {masster-0.4.13 → masster-0.4.14}/src/masster/lib/__init__.py +0 -0
  33. {masster-0.4.13 → masster-0.4.14}/src/masster/lib/lib.py +0 -0
  34. {masster-0.4.13 → masster-0.4.14}/src/masster/logger.py +0 -0
  35. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/__init__.py +0 -0
  36. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/adducts.py +0 -0
  37. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/defaults/__init__.py +0 -0
  38. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/defaults/find_adducts_def.py +0 -0
  39. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/defaults/find_features_def.py +0 -0
  40. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/defaults/find_ms2_def.py +0 -0
  41. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/defaults/get_spectrum_def.py +0 -0
  42. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/defaults/sample_def.py +0 -0
  43. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/h5.py +0 -0
  44. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/helpers.py +0 -0
  45. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/lib.py +0 -0
  46. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/load.py +0 -0
  47. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/parameters.py +0 -0
  48. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/plot.py +0 -0
  49. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/processing.py +0 -0
  50. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/quant.py +0 -0
  51. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/sample5_schema.json +0 -0
  52. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/save.py +0 -0
  53. {masster-0.4.13 → masster-0.4.14}/src/masster/sample/sciex.py +0 -0
  54. {masster-0.4.13 → masster-0.4.14}/src/masster/spectrum.py +0 -0
  55. {masster-0.4.13 → masster-0.4.14}/src/masster/study/__init__.py +0 -0
  56. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/__init__.py +0 -0
  57. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/align_def.py +0 -0
  58. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/export_def.py +0 -0
  59. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/fill_chrom_def.py +0 -0
  60. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/fill_def.py +0 -0
  61. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/find_consensus_def.py +0 -0
  62. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/find_ms2_def.py +0 -0
  63. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/identify_def.py +0 -0
  64. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/integrate_chrom_def.py +0 -0
  65. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/integrate_def.py +0 -0
  66. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/merge_def.py +0 -0
  67. {masster-0.4.13 → masster-0.4.14}/src/masster/study/defaults/study_def.py +0 -0
  68. {masster-0.4.13 → masster-0.4.14}/src/masster/study/export.py +0 -0
  69. {masster-0.4.13 → masster-0.4.14}/src/masster/study/h5.py +0 -0
  70. {masster-0.4.13 → masster-0.4.14}/src/masster/study/helpers.py +0 -0
  71. {masster-0.4.13 → masster-0.4.14}/src/masster/study/id.py +0 -0
  72. {masster-0.4.13 → masster-0.4.14}/src/masster/study/load.py +0 -0
  73. {masster-0.4.13 → masster-0.4.14}/src/masster/study/parameters.py +0 -0
  74. {masster-0.4.13 → masster-0.4.14}/src/masster/study/plot.py +0 -0
  75. {masster-0.4.13 → masster-0.4.14}/src/masster/study/save.py +0 -0
  76. {masster-0.4.13 → masster-0.4.14}/src/masster/study/study5_schema.json +0 -0
  77. {masster-0.4.13 → masster-0.4.14}/tests/conftest.py +0 -0
  78. {masster-0.4.13 → masster-0.4.14}/tests/test_chromatogram.py +0 -0
  79. {masster-0.4.13 → masster-0.4.14}/tests/test_defaults.py +0 -0
  80. {masster-0.4.13 → masster-0.4.14}/tests/test_imports.py +0 -0
  81. {masster-0.4.13 → masster-0.4.14}/tests/test_integration.py +0 -0
  82. {masster-0.4.13 → masster-0.4.14}/tests/test_logger.py +0 -0
  83. {masster-0.4.13 → masster-0.4.14}/tests/test_parameters.py +0 -0
  84. {masster-0.4.13 → masster-0.4.14}/tests/test_sample.py +0 -0
  85. {masster-0.4.13 → masster-0.4.14}/tests/test_spectrum.py +0 -0
  86. {masster-0.4.13 → masster-0.4.14}/tests/test_study.py +0 -0
  87. {masster-0.4.13 → masster-0.4.14}/tests/test_version.py +0 -0
  88. {masster-0.4.13 → masster-0.4.14}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: masster
3
- Version: 0.4.13
3
+ Version: 0.4.14
4
4
  Summary: Mass spectrometry data analysis package
5
5
  Project-URL: homepage, https://github.com/zamboni-lab/masster
6
6
  Project-URL: repository, https://github.com/zamboni-lab/masster
@@ -1,7 +1,7 @@
1
1
 
2
2
  [project]
3
3
  name = "masster"
4
- version = "0.4.13"
4
+ version = "0.4.14"
5
5
  description = "Mass spectrometry data analysis package"
6
6
  authors = [
7
7
  { name = "Zamboni Lab" }
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
 
4
- __version__ = "0.4.13"
4
+ __version__ = "0.4.14"
5
5
 
6
6
 
7
7
  def get_version():
@@ -299,6 +299,47 @@ class Sample:
299
299
  find_ms2_defaults = find_ms2_defaults
300
300
  get_spectrum_defaults = get_spectrum_defaults
301
301
 
302
+ def __dir__(self):
303
+ """
304
+ Custom __dir__ implementation to hide internal methods starting with '_'
305
+ and backward compatibility aliases from tab completion and dir() calls,
306
+ while keeping them accessible to class methods.
307
+
308
+ Returns:
309
+ list: List of public attribute and method names (excluding internal and deprecated methods)
310
+ """
311
+ # Define backward compatibility aliases to hide
312
+ backward_compatibility_aliases = {
313
+ 'load_study', # deprecated alias for load_noms1
314
+ 'filter_features', # alias for filter (deprecated naming)
315
+ 'select_features', # alias for select (deprecated naming)
316
+ 'features_filter', # confusing duplicate of filter
317
+ 'features_select', # confusing duplicate of select
318
+ 'merge_defaults', # alias for find_features_defaults (confusing)
319
+ }
320
+
321
+ # Get all attributes from the class
322
+ all_attrs = set()
323
+
324
+ # Add attributes from the class and all its bases
325
+ for cls in self.__class__.__mro__:
326
+ all_attrs.update(cls.__dict__.keys())
327
+
328
+ # Add instance attributes
329
+ all_attrs.update(self.__dict__.keys())
330
+
331
+ # Filter out attributes starting with '_' (but keep special methods like __init__, __str__, etc.)
332
+ # Also filter out backward compatibility aliases
333
+ public_attrs = [
334
+ attr for attr in all_attrs
335
+ if not attr.startswith('_') or attr.startswith('__') and attr.endswith('__')
336
+ ]
337
+
338
+ # Remove backward compatibility aliases from the public attributes
339
+ public_attrs = [attr for attr in public_attrs if attr not in backward_compatibility_aliases]
340
+
341
+ return sorted(public_attrs)
342
+
302
343
  def logger_update(
303
344
  self,
304
345
  level: str | None = None,
@@ -290,6 +290,85 @@ def merge(self, **kwargs):
290
290
  # Complete merge process
291
291
  self._finalize_merge(link_ms2, min_samples)
292
292
 
293
+ def _perform_adduct_grouping(self, rt_tol, mz_tol):
294
+ """Perform adduct grouping on consensus features."""
295
+ # Add adduct grouping and adduct_of assignment
296
+ if len(self.consensus_df) > 0:
297
+ # Get relevant columns for grouping
298
+ consensus_data = []
299
+ for row in self.consensus_df.iter_rows(named=True):
300
+ consensus_data.append(
301
+ {
302
+ "consensus_uid": row["consensus_uid"],
303
+ "rt": row["rt"],
304
+ "adduct_mass_neutral_top": row.get("adduct_mass_neutral_top"),
305
+ "adduct_top": row.get("adduct_top"),
306
+ "inty_mean": row.get("inty_mean", 0),
307
+ },
308
+ )
309
+
310
+ # Use optimized adduct grouping
311
+ adduct_group_list, adduct_of_list = _optimized_adduct_grouping(
312
+ self, consensus_data, rt_tol, mz_tol
313
+ )
314
+
315
+ # Add the new columns to consensus_df
316
+ self.consensus_df = self.consensus_df.with_columns(
317
+ [
318
+ pl.Series("adduct_group", adduct_group_list, dtype=pl.Int64),
319
+ pl.Series("adduct_of", adduct_of_list, dtype=pl.Int64),
320
+ ],
321
+ )
322
+
323
+ def _finalize_merge(self, link_ms2, min_samples):
324
+ """Complete the merge process with final calculations and cleanup."""
325
+ # Validate min_samples parameter
326
+ if min_samples is None:
327
+ min_samples = 1
328
+ if min_samples < 1:
329
+ min_samples = int(min_samples * len(self.samples_df))
330
+
331
+ # Validate that min_samples doesn't exceed the number of samples
332
+ if min_samples > len(self.samples_df):
333
+ self.logger.warning(
334
+ f"min_samples ({min_samples}) exceeds the number of samples ({len(self.samples_df)}). "
335
+ f"Setting min_samples to {len(self.samples_df)}.",
336
+ )
337
+ min_samples = len(self.samples_df)
338
+
339
+ # Filter out consensus features with less than min_samples features
340
+ l1 = len(self.consensus_df)
341
+ self.consensus_df = self.consensus_df.filter(
342
+ pl.col("number_samples") >= min_samples,
343
+ )
344
+ self.logger.debug(
345
+ f"Filtered {l1 - len(self.consensus_df)} consensus features with less than {min_samples} samples.",
346
+ )
347
+
348
+ # Filter out consensus mapping with less than min_samples features
349
+ self.consensus_mapping_df = self.consensus_mapping_df.filter(
350
+ pl.col("consensus_uid").is_in(self.consensus_df["consensus_uid"].to_list()),
351
+ )
352
+
353
+ # Calculate the completeness of the consensus map
354
+ if len(self.consensus_df) > 0 and len(self.samples_df) > 0:
355
+ c = (
356
+ len(self.consensus_mapping_df)
357
+ / len(self.consensus_df)
358
+ / len(self.samples_df)
359
+ )
360
+ self.logger.info(
361
+ f"Merging completed. Consensus features: {len(self.consensus_df)}. Completeness: {c:.2f}.",
362
+ )
363
+ else:
364
+ self.logger.warning(
365
+ f"Merging completed with empty result. Consensus features: {len(self.consensus_df)}. "
366
+ f"This may be due to min_samples ({min_samples}) being too high for the available data.",
367
+ )
368
+
369
+ if link_ms2:
370
+ self.find_ms2()
371
+
293
372
  def _reset_consensus_data(self):
294
373
  """Reset consensus-related DataFrames at the start of merge."""
295
374
  self.consensus_df = pl.DataFrame()
@@ -605,7 +684,6 @@ def _extract_consensus_features(self, consensus_map, min_samples):
605
684
  total_count = sum(adduct_counts.values())
606
685
  for adduct, count in adduct_counts.items():
607
686
  percentage = (count / total_count) * 100 if total_count > 0 else 0
608
- mass = adduct_masses.get(adduct, None)
609
687
  # Store as list with [name, num, %] format for the adducts column
610
688
  adduct_values.append(
611
689
  [
@@ -872,56 +950,6 @@ def _extract_consensus_features(self, consensus_map, min_samples):
872
950
 
873
951
  self.consensus_map = consensus_map
874
952
 
875
- # Add adduct grouping and adduct_of assignment
876
- if len(self.consensus_df) > 0:
877
- # Get rt_tol and mz_tol from kwargs or use defaults from merge_defaults
878
- adduct_rt_tol = rt_tol # Use the same rt_tol from merge parameters
879
- adduct_mz_tol = mz_tol # Use the same mz_tol from merge parameters
880
-
881
- # Get relevant columns for grouping
882
- consensus_data = []
883
- for row in self.consensus_df.iter_rows(named=True):
884
- consensus_data.append(
885
- {
886
- "consensus_uid": row["consensus_uid"],
887
- "rt": row["rt"],
888
- "adduct_mass_neutral_top": row.get("adduct_mass_neutral_top"),
889
- "adduct_top": row.get("adduct_top"),
890
- "inty_mean": row.get("inty_mean", 0),
891
- },
892
- )
893
-
894
- # Use optimized adduct grouping
895
- adduct_group_list, adduct_of_list = _optimized_adduct_grouping(
896
- self, consensus_data, adduct_rt_tol, adduct_mz_tol
897
- )
898
-
899
- # Add the new columns to consensus_df
900
- self.consensus_df = self.consensus_df.with_columns(
901
- [
902
- pl.Series("adduct_group", adduct_group_list, dtype=pl.Int64),
903
- pl.Series("adduct_of", adduct_of_list, dtype=pl.Int64),
904
- ],
905
- )
906
-
907
- # calculate the completeness of the consensus map
908
- if len(self.consensus_df) > 0 and len(self.samples_df) > 0:
909
- c = (
910
- len(self.consensus_mapping_df)
911
- / len(self.consensus_df)
912
- / len(self.samples_df)
913
- )
914
- self.logger.info(
915
- f"Merging completed. Consensus features: {len(self.consensus_df)}. Completeness: {c:.2f}.",
916
- )
917
- else:
918
- self.logger.warning(
919
- f"Merging completed with empty result. Consensus features: {len(self.consensus_df)}. "
920
- f"This may be due to min_samples ({min_samples}) being too high for the available data.",
921
- )
922
- if link_ms2:
923
- self.find_ms2()
924
-
925
953
 
926
954
  def _optimized_feature_lookup(study_obj, features_df):
927
955
  """
@@ -119,6 +119,13 @@ from masster.study.processing import align
119
119
  from masster.study.processing import merge
120
120
  from masster.study.processing import integrate
121
121
  from masster.study.processing import find_ms2
122
+ from masster.study.processing import _reset_consensus_data
123
+ from masster.study.processing import _process_merge_parameters
124
+ from masster.study.processing import _validate_merge_inputs
125
+ from masster.study.processing import _perform_feature_grouping
126
+ from masster.study.processing import _extract_consensus_features
127
+ from masster.study.processing import _perform_adduct_grouping
128
+ from masster.study.processing import _finalize_merge
122
129
  from masster.study.parameters import store_history
123
130
  from masster.study.parameters import get_parameters
124
131
  from masster.study.parameters import update_parameters
@@ -490,6 +497,15 @@ class Study:
490
497
  _format_adduct_name = _format_adduct_name
491
498
  _parse_element_counts = _parse_element_counts
492
499
 
500
+ # === Merge Helper Methods ===
501
+ _reset_consensus_data = _reset_consensus_data
502
+ _process_merge_parameters = _process_merge_parameters
503
+ _validate_merge_inputs = _validate_merge_inputs
504
+ _perform_feature_grouping = _perform_feature_grouping
505
+ _extract_consensus_features = _extract_consensus_features
506
+ _perform_adduct_grouping = _perform_adduct_grouping
507
+ _finalize_merge = _finalize_merge
508
+
493
509
  # === Default Parameters ===
494
510
  study_defaults = study_defaults
495
511
  align_defaults = align_defaults
@@ -587,6 +603,51 @@ class Study:
587
603
  except Exception as e:
588
604
  self.logger.error(f"Failed to reload current module {current_module}: {e}")
589
605
 
606
+ def __dir__(self):
607
+ """
608
+ Custom __dir__ implementation to hide internal methods starting with '_'
609
+ and backward compatibility aliases from tab completion and dir() calls,
610
+ while keeping them accessible to class methods.
611
+
612
+ Returns:
613
+ list: List of public attribute and method names (excluding internal and deprecated methods)
614
+ """
615
+ # Define backward compatibility aliases to hide
616
+ backward_compatibility_aliases = {
617
+ 'add_folder', # alias for add
618
+ 'find_consensus', # alias for merge
619
+ 'integrate_chrom', # alias for integrate
620
+ 'fill_chrom', # alias for fill
621
+ 'fill_chrom_single', # alias for fill_single
622
+ 'filter_consensus', # alias for consensus_filter
623
+ 'select_consensus', # alias for consensus_select
624
+ 'filter_features', # alias for features_filter
625
+ 'select_features', # alias for features_select
626
+ 'consensus_find', # alias for merge
627
+ }
628
+
629
+ # Get all attributes from the class
630
+ all_attrs = set()
631
+
632
+ # Add attributes from the class and all its bases
633
+ for cls in self.__class__.__mro__:
634
+ all_attrs.update(cls.__dict__.keys())
635
+
636
+ # Add instance attributes
637
+ all_attrs.update(self.__dict__.keys())
638
+
639
+ # Filter out attributes starting with '_' (but keep special methods like __init__, __str__, etc.)
640
+ # Also filter out backward compatibility aliases
641
+ public_attrs = [
642
+ attr for attr in all_attrs
643
+ if not attr.startswith('_') or attr.startswith('__') and attr.endswith('__')
644
+ ]
645
+
646
+ # Remove backward compatibility aliases from the public attributes
647
+ public_attrs = [attr for attr in public_attrs if attr not in backward_compatibility_aliases]
648
+
649
+ return sorted(public_attrs)
650
+
590
651
  def __str__(self):
591
652
  """
592
653
  Returns a string representation of the study.
@@ -1374,7 +1374,7 @@ wheels = [
1374
1374
 
1375
1375
  [[package]]
1376
1376
  name = "masster"
1377
- version = "0.4.13"
1377
+ version = "0.4.14"
1378
1378
  source = { editable = "." }
1379
1379
  dependencies = [
1380
1380
  { name = "alpharaw" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes