masster 0.2.4__py3-none-any.whl → 0.3.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 masster might be problematic. Click here for more details.

Files changed (55) hide show
  1. masster/__init__.py +27 -27
  2. masster/_version.py +17 -17
  3. masster/chromatogram.py +497 -503
  4. masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.featureXML +199787 -0
  5. masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.sample5 +0 -0
  6. masster/logger.py +318 -244
  7. masster/sample/__init__.py +9 -9
  8. masster/sample/defaults/__init__.py +15 -15
  9. masster/sample/defaults/find_adducts_def.py +325 -325
  10. masster/sample/defaults/find_features_def.py +366 -366
  11. masster/sample/defaults/find_ms2_def.py +285 -285
  12. masster/sample/defaults/get_spectrum_def.py +314 -318
  13. masster/sample/defaults/sample_def.py +374 -378
  14. masster/sample/h5.py +1321 -1297
  15. masster/sample/helpers.py +833 -364
  16. masster/sample/lib.py +762 -0
  17. masster/sample/load.py +1220 -1187
  18. masster/sample/parameters.py +131 -131
  19. masster/sample/plot.py +1610 -1622
  20. masster/sample/processing.py +1402 -1416
  21. masster/sample/quant.py +209 -0
  22. masster/sample/sample.py +391 -387
  23. masster/sample/sample5_schema.json +181 -181
  24. masster/sample/save.py +737 -719
  25. masster/sample/sciex.py +1213 -0
  26. masster/spectrum.py +1287 -1319
  27. masster/study/__init__.py +9 -9
  28. masster/study/defaults/__init__.py +21 -19
  29. masster/study/defaults/align_def.py +267 -267
  30. masster/study/defaults/export_def.py +41 -40
  31. masster/study/defaults/fill_chrom_def.py +264 -264
  32. masster/study/defaults/fill_def.py +260 -0
  33. masster/study/defaults/find_consensus_def.py +256 -256
  34. masster/study/defaults/find_ms2_def.py +163 -163
  35. masster/study/defaults/integrate_chrom_def.py +225 -225
  36. masster/study/defaults/integrate_def.py +221 -0
  37. masster/study/defaults/merge_def.py +256 -0
  38. masster/study/defaults/study_def.py +272 -269
  39. masster/study/export.py +674 -287
  40. masster/study/h5.py +1398 -886
  41. masster/study/helpers.py +1650 -433
  42. masster/study/helpers_optimized.py +317 -0
  43. masster/study/load.py +1201 -1078
  44. masster/study/parameters.py +99 -99
  45. masster/study/plot.py +632 -645
  46. masster/study/processing.py +1057 -1046
  47. masster/study/save.py +149 -134
  48. masster/study/study.py +606 -522
  49. masster/study/study5_schema.json +247 -241
  50. {masster-0.2.4.dist-info → masster-0.3.0.dist-info}/METADATA +15 -10
  51. masster-0.3.0.dist-info/RECORD +59 -0
  52. {masster-0.2.4.dist-info → masster-0.3.0.dist-info}/licenses/LICENSE +661 -661
  53. masster-0.2.4.dist-info/RECORD +0 -50
  54. {masster-0.2.4.dist-info → masster-0.3.0.dist-info}/WHEEL +0 -0
  55. {masster-0.2.4.dist-info → masster-0.3.0.dist-info}/entry_points.txt +0 -0
masster/logger.py CHANGED
@@ -1,244 +1,318 @@
1
- # masster/logger.py
2
- """
3
- Simple logger system for masster Study and Sample instances.
4
- Uses basic Python logging timestamp = dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
5
-
6
- # Loguru-style colors for different log levels
7
- level_colors = {
8
- 'TRACE': '\x1b[90m', # bright black (gray)
9
- 'DEBUG': '\x1b[36m', # cyan
10
- 'INFO': '\x1b[34m', # blue
11
- 'SUCCESS': '\x1b[32m', # green
12
- 'WARNING': '\x1b[33m', # yellow
13
- 'ERROR': '\x1b[31m', # red
14
- 'CRITICAL': '\x1b[35m', # magenta
15
- }
16
-
17
- level_str = record.levelname.ljust(8)complex loguru filtering.
18
- """
19
- from __future__ import annotations
20
- import sys
21
- import uuid
22
- import logging
23
- import datetime
24
- from typing import Any, Optional
25
-
26
-
27
- class MassterLogger:
28
- """Simple logger wrapper for Study/Sample instances.
29
- Each instance gets its own Python logger to avoid conflicts.
30
-
31
- Args:
32
- instance_type: Type of instance ("study" or "sample")
33
- instance_id: Unique identifier for this instance (auto-generated if None)
34
- level: Logging level ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
35
- label: Custom label to include in log messages
36
- sink: Output sink (defaults to sys.stdout)
37
- """
38
-
39
- def __init__(
40
- self,
41
- instance_type: str,
42
- instance_id: Optional[str] = None,
43
- level: str = "INFO",
44
- label: str = "",
45
- sink: Optional[Any] = None
46
- ):
47
- if instance_id is None:
48
- instance_id = str(uuid.uuid4())[:8]
49
- self.instance_type = instance_type.lower()
50
- self.instance_id = instance_id
51
- self.level = level.upper()
52
- self.label = label
53
-
54
- # Convert string sink to actual object
55
- if sink == "sys.stdout" or sink is None:
56
- self.sink = sys.stdout
57
- else:
58
- self.sink = sink
59
-
60
- # Create a unique logger name for this instance
61
- self.logger_name = f"masster.{self.instance_type}.{self.instance_id}"
62
-
63
- # Get a Python logger instance
64
- self.logger_instance = logging.getLogger(self.logger_name)
65
-
66
- # Remove any existing handlers to prevent duplicates
67
- if self.logger_instance.hasHandlers():
68
- self.logger_instance.handlers.clear()
69
-
70
- self.logger_instance.setLevel(getattr(logging, self.level))
71
-
72
- # Create a stream handler
73
- self.handler = logging.StreamHandler(self.sink)
74
-
75
- # Create formatter that matches the original masster style
76
- class massterFormatter(logging.Formatter):
77
- def __init__(self, label):
78
- super().__init__()
79
- self.label = label
80
-
81
- def format(self, record):
82
- # Create timestamp in the same format as loguru
83
- dt = datetime.datetime.fromtimestamp(record.created)
84
- timestamp = dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] # Remove last 3 digits for milliseconds
85
-
86
- # Loguru-style colors for different log levels
87
- level_colors = {
88
- 'TRACE': '\x1b[90m', # bright black (gray)
89
- 'DEBUG': '\x1b[36m', # cyan
90
- 'INFO': '\x1b[37m', # white
91
- 'SUCCESS': '\x1b[32m', # green
92
- 'WARNING': '\x1b[33m', # yellow
93
- 'ERROR': '\x1b[31m', # red
94
- 'CRITICAL': '\x1b[35m', # magenta
95
- }
96
-
97
- level_str = record.levelname.ljust(8)
98
- level_color = level_colors.get(record.levelname, '\x1b[37m') # default white
99
- label_part = self.label if self.label else ""
100
-
101
- # Loguru-style format: <white>timestamp</white> | <level>LEVEL</level> | <cyan>label</cyan> - <level>message</level>
102
- return (f"\x1b[37m{timestamp}\x1b[0m | " # white timestamp
103
- f"{level_color}{level_str}\x1b[0m | " # colored level
104
- f"\x1b[36m{label_part}\x1b[0m" # cyan label
105
- f"{level_color}{record.getMessage()}\x1b[0m") # colored message
106
-
107
- self.handler.setFormatter(massterFormatter(self.label))
108
- self.logger_instance.addHandler(self.handler)
109
-
110
- # Prevent propagation to avoid duplicate messages
111
- self.logger_instance.propagate = False
112
-
113
- def update_level(self, level: str):
114
- """Update the logging level."""
115
- if level.upper() in ["TRACE", "DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL"]:
116
- self.level = level.upper()
117
- self.logger_instance.setLevel(getattr(logging, self.level))
118
- else:
119
- self.warning(f"Invalid logging level '{level}'. Keeping current level: {self.level}")
120
-
121
- def update_label(self, label: str):
122
- """Update the label prefix for log messages."""
123
- self.label = label
124
-
125
- # Update formatter with new label
126
- class massterFormatter(logging.Formatter):
127
- def __init__(self, label):
128
- super().__init__()
129
- self.label = label
130
-
131
- def format(self, record):
132
- dt = datetime.datetime.fromtimestamp(record.created)
133
- timestamp = dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
134
-
135
- # Loguru-style colors for different log levels
136
- level_colors = {
137
- 'TRACE': '\x1b[90m', # bright black (gray)
138
- 'DEBUG': '\x1b[36m', # cyan
139
- 'INFO': '\x1b[37m', # white
140
- 'SUCCESS': '\x1b[32m', # green
141
- 'WARNING': '\x1b[33m', # yellow
142
- 'ERROR': '\x1b[31m', # red
143
- 'CRITICAL': '\x1b[35m', # magenta
144
- }
145
-
146
- level_str = record.levelname.ljust(8)
147
- level_color = level_colors.get(record.levelname, '\x1b[37m') # default white
148
- label_part = self.label if self.label else ""
149
-
150
- # Loguru-style format: <white>timestamp</white> | <level>LEVEL</level> | <cyan>label</cyan> - <level>message</level>
151
- return (f"\x1b[37m{timestamp}\x1b[0m | " # white timestamp
152
- f"{level_color}{level_str}\x1b[0m | " # colored level
153
- f"\x1b[36m{label_part}\x1b[0m" # cyan label
154
- f"{level_color}{record.getMessage()}\x1b[0m") # colored message
155
-
156
- self.handler.setFormatter(massterFormatter(self.label))
157
-
158
- def update_sink(self, sink: Any):
159
- """Update the output sink for log messages."""
160
- # Convert string sink to actual object
161
- if sink == "sys.stdout":
162
- self.sink = sys.stdout
163
- else:
164
- self.sink = sink
165
-
166
- # Remove old handler and create new one with new sink
167
- self.logger_instance.removeHandler(self.handler)
168
- self.handler = logging.StreamHandler(self.sink)
169
-
170
- # Apply formatter
171
- class massterFormatter(logging.Formatter):
172
- def __init__(self, label):
173
- super().__init__()
174
- self.label = label
175
-
176
- def format(self, record):
177
- dt = datetime.datetime.fromtimestamp(record.created)
178
- timestamp = dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
179
-
180
- # Loguru-style colors for different log levels
181
- level_colors = {
182
- 'TRACE': '\x1b[90m', # bright black (gray)
183
- 'DEBUG': '\x1b[36m', # cyan
184
- 'INFO': '\x1b[37m', # white
185
- 'SUCCESS': '\x1b[32m', # green
186
- 'WARNING': '\x1b[33m', # yellow
187
- 'ERROR': '\x1b[31m', # red
188
- 'CRITICAL': '\x1b[35m', # magenta
189
- }
190
-
191
- level_str = record.levelname.ljust(8)
192
- level_color = level_colors.get(record.levelname, '\x1b[37m') # default white
193
- label_part = self.label if self.label else ""
194
-
195
- # Loguru-style format: <white>timestamp</white> | <level>LEVEL</level> | <cyan>label</cyan> - <level>message</level>
196
- return (f"\x1b[37m{timestamp}\x1b[0m | " # white timestamp
197
- f"{level_color}{level_str}\x1b[0m | " # colored level
198
- f"\x1b[36m{label_part}\x1b[0m" # cyan label
199
- f"{level_color}{record.getMessage()}\x1b[0m") # colored message
200
-
201
- self.handler.setFormatter(massterFormatter(self.label))
202
- self.logger_instance.addHandler(self.handler)
203
-
204
- # Logger method delegates
205
- def trace(self, message: str, *args, **kwargs):
206
- """Log a TRACE level message (mapped to DEBUG)."""
207
- self.debug(message, *args, **kwargs)
208
-
209
- def debug(self, message: str, *args, **kwargs):
210
- """Log a DEBUG level message."""
211
- self.logger_instance.debug(message, *args, **kwargs)
212
-
213
- def info(self, message: str, *args, **kwargs):
214
- """Log an INFO level message."""
215
- self.logger_instance.info(message, *args, **kwargs)
216
-
217
- def success(self, message: str, *args, **kwargs):
218
- """Log a SUCCESS level message (mapped to INFO)."""
219
- self.info(message, *args, **kwargs)
220
-
221
- def warning(self, message: str, *args, **kwargs):
222
- """Log a WARNING level message."""
223
- self.logger_instance.warning(message, *args, **kwargs)
224
-
225
- def error(self, message: str, *args, **kwargs):
226
- """Log an ERROR level message."""
227
- self.logger_instance.error(message, *args, **kwargs)
228
-
229
- def critical(self, message: str, *args, **kwargs):
230
- """Log a CRITICAL level message."""
231
- self.logger_instance.critical(message, *args, **kwargs)
232
-
233
- def exception(self, message: str, *args, **kwargs):
234
- """Log an exception with ERROR level."""
235
- self.logger_instance.exception(message, *args, **kwargs)
236
-
237
- def remove(self):
238
- """Remove this logger's handler."""
239
- if self.handler:
240
- self.logger_instance.removeHandler(self.handler)
241
- self.handler = None
242
-
243
- def __repr__(self):
244
- return f"MassterLogger(type={self.instance_type}, id={self.instance_id}, level={self.level})"
1
+ # masster/logger.py
2
+ """
3
+ Simple logger system for masster Study and Sample instances.
4
+ Uses basic Python logging timestamp = dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
5
+
6
+ # Loguru-style colors for different log levels
7
+ level_colors = {
8
+ 'TRACE': '\x1b[34m', # blue
9
+ 'DEBUG': '\x1b[36m', # cyan
10
+ 'INFO': '\x1b[37m', # white
11
+ 'SUCCESS': '\x1b[32m', # green
12
+ 'WARNING': '\x1b[33m', # yellow
13
+ 'ERROR': '\x1b[31m', # red
14
+ 'CRITICAL': '\x1b[35m', # magenta
15
+ }
16
+
17
+ level_str = record.levelname.ljust(8)complex loguru filtering.
18
+ """
19
+
20
+ from __future__ import annotations
21
+ import sys
22
+ import uuid
23
+ import logging
24
+ import datetime
25
+ from typing import Any
26
+
27
+
28
+ class MassterLogger:
29
+ """Simple logger wrapper for Study/Sample instances.
30
+ Each instance gets its own Python logger to avoid conflicts.
31
+
32
+ Args:
33
+ instance_type: Type of instance ("study" or "sample")
34
+ instance_id: Unique identifier for this instance (auto-generated if None)
35
+ level: Logging level ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
36
+ label: Custom label to include in log messages
37
+ sink: Output sink (defaults to sys.stdout)
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ instance_type: str,
43
+ instance_id: str | None = None,
44
+ level: str = "INFO",
45
+ label: str = "",
46
+ sink: Any | None = None,
47
+ ):
48
+ if instance_id is None:
49
+ instance_id = str(uuid.uuid4())[:8]
50
+ self.instance_type = instance_type.lower()
51
+ self.instance_id = instance_id
52
+ self.level = level.upper()
53
+ self.label = label
54
+
55
+ # Convert string sink to actual object
56
+ if sink == "sys.stdout" or sink is None:
57
+ self.sink = sys.stdout
58
+ else:
59
+ self.sink = sink
60
+
61
+ # Create a unique logger name for this instance
62
+ self.logger_name = f"masster.{self.instance_type}.{self.instance_id}"
63
+
64
+ # Get a Python logger instance
65
+ self.logger_instance = logging.getLogger(self.logger_name)
66
+
67
+ # Remove any existing handlers to prevent duplicates
68
+ if self.logger_instance.hasHandlers():
69
+ self.logger_instance.handlers.clear()
70
+
71
+ self.logger_instance.setLevel(getattr(logging, self.level))
72
+
73
+ # Create a stream handler
74
+ self.handler = logging.StreamHandler(self.sink)
75
+
76
+ # Create formatter that matches the original masster style
77
+ class massterFormatter(logging.Formatter):
78
+ def __init__(self, label):
79
+ super().__init__()
80
+ self.label = label
81
+
82
+ def format(self, record):
83
+ # Create timestamp in the same format as loguru
84
+ dt = datetime.datetime.fromtimestamp(record.created)
85
+ timestamp = dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] # Remove last 3 digits for milliseconds
86
+
87
+ # Loguru-style colors for different log levels
88
+ level_colors = {
89
+ 'TRACE': '\x1b[34m', # blue
90
+ 'DEBUG': '\x1b[36m', # cyan
91
+ 'INFO': '\x1b[37m', # white
92
+ 'SUCCESS': '\x1b[32m', # green
93
+ 'WARNING': '\x1b[33m', # yellow
94
+ 'ERROR': '\x1b[31m', # red
95
+ 'CRITICAL': '\x1b[35m', # magenta
96
+ }
97
+
98
+ level_str = record.levelname.ljust(8)
99
+ level_color = level_colors.get(record.levelname, '\x1b[37m') # default white
100
+ label_part = self.label + " | " if self.label else ""
101
+
102
+ # For DEBUG and TRACE levels, add module/location information
103
+ location_info = ""
104
+ if record.levelname in ['TRACE']:
105
+ # Use caller information if available (from extra), otherwise fall back to record info
106
+ if hasattr(record, 'caller_module'):
107
+ module_name = record.caller_module.split('.')[-1] if record.caller_module else 'unknown'
108
+ line_no = record.caller_lineno
109
+ func_name = record.caller_funcname
110
+ else:
111
+ module_name = record.module if hasattr(record, 'module') else 'unknown'
112
+ line_no = record.lineno
113
+ func_name = record.funcName
114
+ location_info = f"\x1b[90m{module_name}:{func_name}:{line_no}\x1b[0m | " # dim gray for location info
115
+
116
+ # Loguru-style format: <white>timestamp</white> | <level>LEVEL</level> | <location> | <cyan>label</cyan> - <level>message</level>
117
+ return (f"\x1b[37m{timestamp}\x1b[0m | " # white timestamp
118
+ f"{level_color}{level_str}\x1b[0m | " # colored level
119
+ f"{location_info}" # location info for DEBUG/TRACE
120
+ f"{level_color}{label_part}\x1b[0m" # colored label
121
+ f"{level_color}{record.getMessage()}\x1b[0m") # colored message
122
+
123
+ self.handler.setFormatter(massterFormatter(self.label))
124
+ self.logger_instance.addHandler(self.handler)
125
+
126
+ # Prevent propagation to avoid duplicate messages
127
+ self.logger_instance.propagate = False
128
+
129
+ def update_level(self, level: str):
130
+ """Update the logging level."""
131
+ if level.upper() in ["TRACE", "DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL"]:
132
+ self.level = level.upper()
133
+ self.logger_instance.setLevel(getattr(logging, self.level))
134
+ else:
135
+ self.warning(f"Invalid logging level '{level}'. Keeping current level: {self.level}")
136
+
137
+ def update_label(self, label: str):
138
+ """Update the label prefix for log messages."""
139
+ self.label = label
140
+
141
+ # Update formatter with new label
142
+ class massterFormatter(logging.Formatter):
143
+ def __init__(self, label):
144
+ super().__init__()
145
+ self.label = label
146
+
147
+ def format(self, record):
148
+ dt = datetime.datetime.fromtimestamp(record.created)
149
+ timestamp = dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
150
+
151
+ # Loguru-style colors for different log levels
152
+ level_colors = {
153
+ 'TRACE': '\x1b[34m', # blue
154
+ 'DEBUG': '\x1b[36m', # cyan
155
+ 'INFO': '\x1b[37m', # white
156
+ 'SUCCESS': '\x1b[32m', # green
157
+ 'WARNING': '\x1b[33m', # yellow
158
+ 'ERROR': '\x1b[31m', # red
159
+ 'CRITICAL': '\x1b[35m', # magenta
160
+ }
161
+
162
+ level_str = record.levelname.ljust(8)
163
+ level_color = level_colors.get(record.levelname, '\x1b[37m') # default white
164
+ label_part = self.label + " | " if self.label else ""
165
+
166
+ # For DEBUG and TRACE levels, add module/location information
167
+ location_info = ""
168
+ if record.levelname in ['TRACE']:
169
+ # Use caller information if available (from extra), otherwise fall back to record info
170
+ if hasattr(record, 'caller_module'):
171
+ module_name = record.caller_module.split('.')[-1] if record.caller_module else 'unknown'
172
+ line_no = record.caller_lineno
173
+ func_name = record.caller_funcname
174
+ else:
175
+ module_name = record.module if hasattr(record, 'module') else 'unknown'
176
+ line_no = record.lineno
177
+ func_name = record.funcName
178
+ location_info = f"\x1b[90m{module_name}:{func_name}:{line_no}\x1b[0m | " # dim gray for location info
179
+
180
+ # Loguru-style format: <white>timestamp</white> | <level>LEVEL</level> | <location> | <cyan>label</cyan> - <level>message</level>
181
+ return (f"\x1b[37m{timestamp}\x1b[0m | " # white timestamp
182
+ f"{level_color}{level_str}\x1b[0m | " # colored level
183
+ f"{location_info}" # location info for DEBUG/TRACE
184
+ f"{level_color}{label_part}\x1b[0m" # colored label
185
+ f"{level_color}{record.getMessage()}\x1b[0m") # colored message
186
+
187
+ self.handler.setFormatter(massterFormatter(self.label))
188
+
189
+ def update_sink(self, sink: Any):
190
+ """Update the output sink for log messages."""
191
+ # Convert string sink to actual object
192
+ if sink == "sys.stdout":
193
+ self.sink = sys.stdout
194
+ else:
195
+ self.sink = sink
196
+
197
+ # Remove old handler and create new one with new sink
198
+ self.logger_instance.removeHandler(self.handler)
199
+ self.handler = logging.StreamHandler(self.sink)
200
+
201
+ # Apply formatter
202
+ class massterFormatter(logging.Formatter):
203
+ def __init__(self, label):
204
+ super().__init__()
205
+ self.label = label
206
+
207
+ def format(self, record):
208
+ dt = datetime.datetime.fromtimestamp(record.created)
209
+ timestamp = dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
210
+
211
+ # Loguru-style colors for different log levels
212
+ level_colors = {
213
+ 'TRACE': '\x1b[34m', # blue
214
+ 'DEBUG': '\x1b[36m', # cyan
215
+ 'INFO': '\x1b[37m', # white
216
+ 'SUCCESS': '\x1b[32m', # green
217
+ 'WARNING': '\x1b[33m', # yellow
218
+ 'ERROR': '\x1b[31m', # red
219
+ 'CRITICAL': '\x1b[35m', # magenta
220
+ }
221
+
222
+ level_str = record.levelname.ljust(8)
223
+ level_color = level_colors.get(record.levelname, '\x1b[37m') # default white
224
+ label_part = self.label + " | " if self.label else ""
225
+
226
+ # For DEBUG and TRACE levels, add module/location information
227
+ location_info = ""
228
+ if record.levelname in ['TRACE']:
229
+ # Use caller information if available (from extra), otherwise fall back to record info
230
+ if hasattr(record, 'caller_module'):
231
+ module_name = record.caller_module.split('.')[-1] if record.caller_module else 'unknown'
232
+ line_no = record.caller_lineno
233
+ func_name = record.caller_funcname
234
+ else:
235
+ module_name = record.module
236
+ line_no = record.lineno
237
+ func_name = record.funcName
238
+ location_info = f"\x1b[90m{module_name}:{func_name}:{line_no}\x1b[0m | " # dim gray for location info
239
+
240
+ # Loguru-style format: <white>timestamp</white> | <level>LEVEL</level> | <location> | <cyan>label</cyan> - <level>message</level>
241
+ return (f"\x1b[37m{timestamp}\x1b[0m | " # white timestamp
242
+ f"{level_color}{level_str}\x1b[0m | " # colored level
243
+ f"{location_info}" # location info for DEBUG/TRACE
244
+ f"{level_color}{label_part}\x1b[0m" # colored label
245
+ f"{level_color}{record.getMessage()}\x1b[0m") # colored message
246
+
247
+ self.handler.setFormatter(massterFormatter(self.label))
248
+ self.logger_instance.addHandler(self.handler)
249
+
250
+ # Logger method delegates
251
+ def trace(self, message: str, *args, **kwargs):
252
+ """Log a TRACE level message (mapped to DEBUG)."""
253
+ # Get caller frame information (skip this method and go to actual caller)
254
+ import inspect
255
+ frame = inspect.currentframe().f_back
256
+
257
+ # Add caller information as extra parameters
258
+ extra = kwargs.get('extra', {})
259
+ extra.update({
260
+ 'caller_module': frame.f_globals.get('__name__', 'unknown'),
261
+ 'caller_filename': frame.f_code.co_filename,
262
+ 'caller_lineno': frame.f_lineno,
263
+ 'caller_funcname': frame.f_code.co_name
264
+ })
265
+ kwargs['extra'] = extra
266
+
267
+ self.logger_instance.debug(message, *args, **kwargs)
268
+
269
+ def debug(self, message: str, *args, **kwargs):
270
+ """Log a DEBUG level message."""
271
+ # Get caller frame information (skip this method and go to actual caller)
272
+ import inspect
273
+ frame = inspect.currentframe().f_back
274
+
275
+ # Add caller information as extra parameters
276
+ extra = kwargs.get('extra', {})
277
+ extra.update({
278
+ 'caller_module': frame.f_globals.get('__name__', 'unknown'),
279
+ 'caller_filename': frame.f_code.co_filename,
280
+ 'caller_lineno': frame.f_lineno,
281
+ 'caller_funcname': frame.f_code.co_name
282
+ })
283
+ kwargs['extra'] = extra
284
+
285
+ self.logger_instance.debug(message, *args, **kwargs)
286
+
287
+ def info(self, message: str, *args, **kwargs):
288
+ """Log an INFO level message."""
289
+ self.logger_instance.info(message, *args, **kwargs)
290
+
291
+ def success(self, message: str, *args, **kwargs):
292
+ """Log a SUCCESS level message (mapped to INFO)."""
293
+ self.info(message, *args, **kwargs)
294
+
295
+ def warning(self, message: str, *args, **kwargs):
296
+ """Log a WARNING level message."""
297
+ self.logger_instance.warning(message, *args, **kwargs)
298
+
299
+ def error(self, message: str, *args, **kwargs):
300
+ """Log an ERROR level message."""
301
+ self.logger_instance.error(message, *args, **kwargs)
302
+
303
+ def critical(self, message: str, *args, **kwargs):
304
+ """Log a CRITICAL level message."""
305
+ self.logger_instance.critical(message, *args, **kwargs)
306
+
307
+ def exception(self, message: str, *args, **kwargs):
308
+ """Log an exception with ERROR level."""
309
+ self.logger_instance.exception(message, *args, **kwargs)
310
+
311
+ def remove(self):
312
+ """Remove this logger's handler."""
313
+ if self.handler:
314
+ self.logger_instance.removeHandler(self.handler)
315
+ self.handler = None
316
+
317
+ def __repr__(self):
318
+ return f"MassterLogger(type={self.instance_type}, id={self.instance_id}, level={self.level})"
@@ -1,9 +1,9 @@
1
- """
2
- Sample module for masster.
3
-
4
- This module provides the Sample class for handling mass spectrometry data.
5
- """
6
-
7
- from .sample import Sample
8
-
9
- __all__ = ["Sample"]
1
+ """
2
+ Sample module for masster.
3
+
4
+ This module provides the Sample class for handling mass spectrometry data.
5
+ """
6
+
7
+ from .sample import Sample
8
+
9
+ __all__ = ["Sample"]
@@ -1,15 +1,15 @@
1
- """Sample defaults initialization."""
2
-
3
- from .find_adducts_def import find_adducts_defaults
4
- from .find_features_def import find_features_defaults
5
- from .find_ms2_def import find_ms2_defaults
6
- from .get_spectrum_def import get_spectrum_defaults
7
- from .sample_def import sample_defaults
8
-
9
- __all__ = [
10
- "find_adducts_defaults",
11
- "find_features_defaults",
12
- "find_ms2_defaults",
13
- "get_spectrum_defaults",
14
- "sample_defaults",
15
- ]
1
+ """Sample defaults initialization."""
2
+
3
+ from .find_adducts_def import find_adducts_defaults
4
+ from .find_features_def import find_features_defaults
5
+ from .find_ms2_def import find_ms2_defaults
6
+ from .get_spectrum_def import get_spectrum_defaults
7
+ from .sample_def import sample_defaults
8
+
9
+ __all__ = [
10
+ "find_adducts_defaults",
11
+ "find_features_defaults",
12
+ "find_ms2_defaults",
13
+ "get_spectrum_defaults",
14
+ "sample_defaults",
15
+ ]