additory 0.1.0a4__py3-none-any.whl → 0.1.1a1__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.
- additory/__init__.py +58 -14
- additory/common/__init__.py +31 -147
- additory/common/column_selector.py +255 -0
- additory/common/distributions.py +286 -613
- additory/common/extractors.py +313 -0
- additory/common/knn_imputation.py +332 -0
- additory/common/result.py +380 -0
- additory/common/strategy_parser.py +243 -0
- additory/common/unit_conversions.py +338 -0
- additory/common/validation.py +283 -103
- additory/core/__init__.py +34 -22
- additory/core/backend.py +258 -0
- additory/core/config.py +177 -305
- additory/core/logging.py +230 -24
- additory/core/memory_manager.py +157 -495
- additory/expressions/__init__.py +2 -23
- additory/expressions/compiler.py +457 -0
- additory/expressions/engine.py +264 -487
- additory/expressions/integrity.py +179 -0
- additory/expressions/loader.py +263 -0
- additory/expressions/parser.py +363 -167
- additory/expressions/resolver.py +274 -0
- additory/functions/__init__.py +1 -0
- additory/functions/analyze/__init__.py +144 -0
- additory/functions/analyze/cardinality.py +58 -0
- additory/functions/analyze/correlations.py +66 -0
- additory/functions/analyze/distributions.py +53 -0
- additory/functions/analyze/duplicates.py +49 -0
- additory/functions/analyze/features.py +61 -0
- additory/functions/analyze/imputation.py +66 -0
- additory/functions/analyze/outliers.py +65 -0
- additory/functions/analyze/patterns.py +65 -0
- additory/functions/analyze/presets.py +72 -0
- additory/functions/analyze/quality.py +59 -0
- additory/functions/analyze/timeseries.py +53 -0
- additory/functions/analyze/types.py +45 -0
- additory/functions/expressions/__init__.py +161 -0
- additory/functions/snapshot/__init__.py +82 -0
- additory/functions/snapshot/filter.py +119 -0
- additory/functions/synthetic/__init__.py +113 -0
- additory/functions/synthetic/mode_detector.py +47 -0
- additory/functions/synthetic/strategies/__init__.py +1 -0
- additory/functions/synthetic/strategies/advanced.py +35 -0
- additory/functions/synthetic/strategies/augmentative.py +160 -0
- additory/functions/synthetic/strategies/generative.py +168 -0
- additory/functions/synthetic/strategies/presets.py +116 -0
- additory/functions/to/__init__.py +188 -0
- additory/functions/to/lookup.py +351 -0
- additory/functions/to/merge.py +189 -0
- additory/functions/to/sort.py +91 -0
- additory/functions/to/summarize.py +170 -0
- additory/functions/transform/__init__.py +140 -0
- additory/functions/transform/datetime.py +79 -0
- additory/functions/transform/extract.py +85 -0
- additory/functions/transform/harmonize.py +105 -0
- additory/functions/transform/knn.py +62 -0
- additory/functions/transform/onehotencoding.py +68 -0
- additory/functions/transform/transpose.py +42 -0
- additory-0.1.1a1.dist-info/METADATA +83 -0
- additory-0.1.1a1.dist-info/RECORD +62 -0
- additory/analysis/__init__.py +0 -48
- additory/analysis/cardinality.py +0 -126
- additory/analysis/correlations.py +0 -124
- additory/analysis/distributions.py +0 -376
- additory/analysis/quality.py +0 -158
- additory/analysis/scan.py +0 -400
- additory/common/backend.py +0 -371
- additory/common/column_utils.py +0 -191
- additory/common/exceptions.py +0 -62
- additory/common/lists.py +0 -229
- additory/common/patterns.py +0 -240
- additory/common/resolver.py +0 -567
- additory/common/sample_data.py +0 -182
- additory/core/ast_builder.py +0 -165
- additory/core/backends/__init__.py +0 -23
- additory/core/backends/arrow_bridge.py +0 -483
- additory/core/backends/cudf_bridge.py +0 -355
- additory/core/column_positioning.py +0 -358
- additory/core/compiler_polars.py +0 -166
- additory/core/enhanced_cache_manager.py +0 -1119
- additory/core/enhanced_matchers.py +0 -473
- additory/core/enhanced_version_manager.py +0 -325
- additory/core/executor.py +0 -59
- additory/core/integrity_manager.py +0 -477
- additory/core/loader.py +0 -190
- additory/core/namespace_manager.py +0 -657
- additory/core/parser.py +0 -176
- additory/core/polars_expression_engine.py +0 -601
- additory/core/registry.py +0 -177
- additory/core/sample_data_manager.py +0 -492
- additory/core/user_namespace.py +0 -751
- additory/core/validator.py +0 -27
- additory/dynamic_api.py +0 -352
- additory/expressions/proxy.py +0 -549
- additory/expressions/registry.py +0 -313
- additory/expressions/samples.py +0 -492
- additory/synthetic/__init__.py +0 -13
- additory/synthetic/column_name_resolver.py +0 -149
- additory/synthetic/deduce.py +0 -259
- additory/synthetic/distributions.py +0 -22
- additory/synthetic/forecast.py +0 -1132
- additory/synthetic/linked_list_parser.py +0 -415
- additory/synthetic/namespace_lookup.py +0 -129
- additory/synthetic/smote.py +0 -320
- additory/synthetic/strategies.py +0 -926
- additory/synthetic/synthesizer.py +0 -713
- additory/utilities/__init__.py +0 -53
- additory/utilities/encoding.py +0 -600
- additory/utilities/games.py +0 -300
- additory/utilities/keys.py +0 -8
- additory/utilities/lookup.py +0 -103
- additory/utilities/matchers.py +0 -216
- additory/utilities/resolvers.py +0 -286
- additory/utilities/settings.py +0 -167
- additory/utilities/units.py +0 -749
- additory/utilities/validators.py +0 -153
- additory-0.1.0a4.dist-info/METADATA +0 -311
- additory-0.1.0a4.dist-info/RECORD +0 -72
- additory-0.1.0a4.dist-info/licenses/LICENSE +0 -21
- {additory-0.1.0a4.dist-info → additory-0.1.1a1.dist-info}/WHEEL +0 -0
- {additory-0.1.0a4.dist-info → additory-0.1.1a1.dist-info}/top_level.txt +0 -0
additory/core/logging.py
CHANGED
|
@@ -1,24 +1,230 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
"""
|
|
2
|
+
Transparent logging system for Additory operations.
|
|
3
|
+
|
|
4
|
+
Provides clear, actionable messages about:
|
|
5
|
+
- Information: Assumptions and defaults
|
|
6
|
+
- Warnings: Why processing stopped
|
|
7
|
+
- Errors: Where errors occurred
|
|
8
|
+
|
|
9
|
+
Principle: "If it feels like magic, explain it!"
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import Dict, List, Optional
|
|
14
|
+
import json
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Logger:
|
|
18
|
+
"""
|
|
19
|
+
Centralized logger for all additory operations.
|
|
20
|
+
|
|
21
|
+
Provides three levels of logging:
|
|
22
|
+
- info: Explain assumptions and defaults
|
|
23
|
+
- warning: Explain why processing stopped
|
|
24
|
+
- error: Show where error occurred
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, level: str = 'info'):
|
|
28
|
+
"""
|
|
29
|
+
Initialize logger with level.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
level: Logging level ('info', 'warning', 'error', 'silent')
|
|
33
|
+
"""
|
|
34
|
+
self.level = level
|
|
35
|
+
self.context: Dict = {}
|
|
36
|
+
self.messages: List[Dict] = []
|
|
37
|
+
self._validate_level(level)
|
|
38
|
+
|
|
39
|
+
def _validate_level(self, level: str) -> None:
|
|
40
|
+
"""Validate logging level."""
|
|
41
|
+
valid_levels = ['info', 'warning', 'error', 'silent']
|
|
42
|
+
if level not in valid_levels:
|
|
43
|
+
raise ValueError(f"Invalid log level '{level}'. Must be one of: {valid_levels}")
|
|
44
|
+
|
|
45
|
+
def set_level(self, level: str) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Set logging level.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
level: New logging level ('info', 'warning', 'error', 'silent')
|
|
51
|
+
"""
|
|
52
|
+
self._validate_level(level)
|
|
53
|
+
self.level = level
|
|
54
|
+
|
|
55
|
+
def set_context(self, operation: str, details: Optional[Dict] = None) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Set current operation context.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
operation: Operation name ('to', 'transform', 'snapshot', 'synthetic', 'analyze')
|
|
61
|
+
details: Optional operation details
|
|
62
|
+
"""
|
|
63
|
+
self.context = {
|
|
64
|
+
'operation': operation,
|
|
65
|
+
'details': details or {},
|
|
66
|
+
'timestamp': datetime.now().isoformat()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
def info(self, message: str, details: Optional[Dict] = None) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Log information message (assumptions, defaults).
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
message: Information message
|
|
75
|
+
details: Optional additional details
|
|
76
|
+
|
|
77
|
+
Example:
|
|
78
|
+
logger.info("Using 'fetch if unique' mode for column 'price'")
|
|
79
|
+
logger.info("Detected pandas DataFrame, converting to Polars")
|
|
80
|
+
"""
|
|
81
|
+
if self.level == 'info':
|
|
82
|
+
self._log('info', message, details)
|
|
83
|
+
|
|
84
|
+
def warning(self, message: str, details: Optional[Dict] = None) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Log warning message (why processing stopped).
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
message: Warning message
|
|
90
|
+
details: Optional additional details
|
|
91
|
+
|
|
92
|
+
Example:
|
|
93
|
+
logger.warning("Many-to-many relationship detected, cannot proceed")
|
|
94
|
+
logger.warning("Duplicate expression name 'bmi' found")
|
|
95
|
+
"""
|
|
96
|
+
if self.level in ['info', 'warning']:
|
|
97
|
+
self._log('warning', message, details)
|
|
98
|
+
|
|
99
|
+
def error(self, message: str, error_location: str, details: Optional[Dict] = None) -> None:
|
|
100
|
+
"""
|
|
101
|
+
Log error message (where error occurred).
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
message: Error message
|
|
105
|
+
error_location: Where error occurred ('df', 'expression', 'strategy', etc.)
|
|
106
|
+
details: Optional additional details
|
|
107
|
+
|
|
108
|
+
Example:
|
|
109
|
+
logger.error("Column 'age' not found", error_location='df')
|
|
110
|
+
logger.error("Division by zero", error_location='expression')
|
|
111
|
+
"""
|
|
112
|
+
if self.level != 'silent':
|
|
113
|
+
error_details = details or {}
|
|
114
|
+
error_details['error_location'] = error_location
|
|
115
|
+
self._log('error', message, error_details)
|
|
116
|
+
|
|
117
|
+
def _log(self, level: str, message: str, details: Optional[Dict] = None) -> None:
|
|
118
|
+
"""Internal method to log a message."""
|
|
119
|
+
log_entry = {
|
|
120
|
+
'level': level,
|
|
121
|
+
'message': message,
|
|
122
|
+
'context': self.context.copy(),
|
|
123
|
+
'details': details or {},
|
|
124
|
+
'timestamp': datetime.now().isoformat()
|
|
125
|
+
}
|
|
126
|
+
self.messages.append(log_entry)
|
|
127
|
+
|
|
128
|
+
# Print formatted message
|
|
129
|
+
formatted = format_message(level, message, self.context, details or {})
|
|
130
|
+
print(formatted)
|
|
131
|
+
|
|
132
|
+
def get_messages(self, level: Optional[str] = None) -> List[Dict]:
|
|
133
|
+
"""
|
|
134
|
+
Get logged messages.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
level: Filter by level (None = all)
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
List of message dictionaries
|
|
141
|
+
"""
|
|
142
|
+
if level is None:
|
|
143
|
+
return self.messages.copy()
|
|
144
|
+
return [msg for msg in self.messages if msg['level'] == level]
|
|
145
|
+
|
|
146
|
+
def clear(self) -> None:
|
|
147
|
+
"""Clear all logged messages."""
|
|
148
|
+
self.messages.clear()
|
|
149
|
+
self.context.clear()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Global logger instance
|
|
153
|
+
_global_logger: Optional[Logger] = None
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def get_logger() -> Logger:
|
|
157
|
+
"""
|
|
158
|
+
Get the global logger instance.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Global Logger instance
|
|
162
|
+
|
|
163
|
+
Example:
|
|
164
|
+
logger = get_logger()
|
|
165
|
+
logger.info("Processing started")
|
|
166
|
+
"""
|
|
167
|
+
global _global_logger
|
|
168
|
+
if _global_logger is None:
|
|
169
|
+
_global_logger = Logger()
|
|
170
|
+
return _global_logger
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def set_log_level(level: str) -> None:
|
|
174
|
+
"""
|
|
175
|
+
Set global logging level.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
level: Logging level ('info', 'warning', 'error', 'silent')
|
|
179
|
+
|
|
180
|
+
Example:
|
|
181
|
+
import additory
|
|
182
|
+
additory.add.set_log_level('warning')
|
|
183
|
+
"""
|
|
184
|
+
logger = get_logger()
|
|
185
|
+
logger.set_level(level)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def format_message(level: str, message: str, context: Dict, details: Dict) -> str:
|
|
189
|
+
"""
|
|
190
|
+
Format log message for display.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
level: Message level
|
|
194
|
+
message: Message text
|
|
195
|
+
context: Operation context
|
|
196
|
+
details: Additional details
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Formatted message string
|
|
200
|
+
"""
|
|
201
|
+
# Level prefix with emoji
|
|
202
|
+
level_prefix = {
|
|
203
|
+
'info': 'ℹ️ INFO',
|
|
204
|
+
'warning': '⚠️ WARNING',
|
|
205
|
+
'error': '❌ ERROR'
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
prefix = level_prefix.get(level, level.upper())
|
|
209
|
+
|
|
210
|
+
# Build message
|
|
211
|
+
parts = [f"[{prefix}]"]
|
|
212
|
+
|
|
213
|
+
# Add context if available
|
|
214
|
+
if context and 'operation' in context:
|
|
215
|
+
parts.append(f"[{context['operation']}]")
|
|
216
|
+
|
|
217
|
+
# Add main message
|
|
218
|
+
parts.append(message)
|
|
219
|
+
|
|
220
|
+
formatted = " ".join(parts)
|
|
221
|
+
|
|
222
|
+
# Add details if available and not empty
|
|
223
|
+
if details and any(details.values()):
|
|
224
|
+
# Filter out None values and format
|
|
225
|
+
clean_details = {k: v for k, v in details.items() if v is not None}
|
|
226
|
+
if clean_details:
|
|
227
|
+
details_str = json.dumps(clean_details, indent=2)
|
|
228
|
+
formatted += f"\n Details: {details_str}"
|
|
229
|
+
|
|
230
|
+
return formatted
|