mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
ProgressTracker attached ConsoleProgressDisplay unconditionally, so any script or CI job that piped or redirected stdout had one progress bar per stage written into its output, escape sequences included. A plain `python demo.py > out.txt` captured 173 bytes of progress-bar noise around 10 bytes of the program's own output. Console progress is now attached only when stdout is an interactive terminal, when running under Jupyter, or when SEMANTICA_FORCE_PROGRESS is set. FileProgressDisplay is untouched, so progress logging still works in pipelines, and SEMANTICA_DISABLE_PROGRESS keeps its existing meaning and still takes precedence. Both progress environment variables are now documented in the README and the utils reference; SEMANTICA_DISABLE_PROGRESS previously existed only in the reference page. Deviations from the issue: the issue suggested disabling the tracker on non-TTY stdout. This gates the display instead, because disabling the tracker would short-circuit before FileProgressDisplay and take file progress logging down with it, and the ~20 modules that set `progress_tracker.enabled = True` in __init__ would need the property setter taught about TTY state to avoid undoing it. Gating the display leaves both alone. Design note: the claim comment on the issue proposed an `enabled: Optional[bool] = None` constructor opt-in; during implementation the opt-in became SEMANTICA_FORCE_PROGRESS, which needs no signature change and follows the NO_COLOR/FORCE_COLOR convention. Known limitation: TTY detection runs once at tracker construction (the tracker is a process-wide singleton), so a process that redirects stdout after first use needs the env vars to change behaviour. Fixes #1185
9.6 KiB
9.6 KiB
title, description, icon
| title | description | icon |
|---|---|---|
| Utils Module | Shared utilities for logging, validation, error handling, progress tracking, and common operations. | wrench |
semantica.utils provides shared infrastructure used throughout Semantica:
- Structured logging:
setup_logging(),get_logger(),log_execution_timedecorator - Validation helpers:
validate_entity()andvalidate_config()return(bool, Optional[str])without raising - Progress tracking:
ProgressTrackerclass andtrack_progress()iterable wrapper with ETA - Typed exceptions:
SemanticaError,ValidationError,ProcessingError,ConfigurationError,QualityError
Most users won't call utils directly: it's the shared foundation for all modules.
Exported Classes
| Name | Type | Role |
|---|---|---|
setup_logging |
function | Configure the semantica root logger: accepts level, file, console, rotation kwargs |
get_logger |
function | Get a named logger instance (semantica.<name>) |
log_execution_time |
decorator | Wraps a function: logs name, execution time, and success/failure |
log_performance |
function | Log pre-collected performance metrics: log_performance(func_name, execution_time, **metrics) |
validate_entity |
function | Validate entity dict: returns (bool, Optional[str]); does not raise |
validate_config |
function | Validate config dict: returns (bool, Optional[str]); does not raise |
ProgressTracker |
class | Class-based progress tracker with ETA and step callbacks |
track_progress |
function | Wrap any iterable with a live progress bar |
clean_text |
function | Normalize whitespace and strip zero-width control characters |
hash_data |
function | Deterministic SHA-256 hash of a str, bytes, or dict |
SemanticaError |
exception | Base exception for all Semantica errors |
ValidationError |
exception | Raised when input fails validation; has .field, .value, .message |
ProcessingError |
exception | Raised during extraction, graph build, or pipeline step; has .stage |
ConfigurationError |
exception | Raised for configuration validation failures |
QualityError |
exception | Raised when data quality falls below threshold |
What You Get
- Logging — Structured logging with
@log_execution_timedecorator and quality metrics via environment variables. - Validation —
validate_entityandvalidate_configwith a typedValidationErrorcarrying field and value context. - Progress Tracking —
track_progresswraps any iterable: auto-detects console vs Jupyter for the right renderer. - Helper Functions —
clean_text,hash_data,safe_filename, and nested dict utilities used throughout the framework. - Exception Hierarchy —
SemanticaError→ValidationError,ProcessingError: typed exceptions for targeted recovery. - File Utilities —
read_json_fileraisesFileNotFoundErrororjson.JSONDecodeErroron failure: no boilerplate try/except around JSON I/O.
Logging
```python from semantica.utils import setup_logging, get_loggersetup_logging(level="INFO") # "DEBUG" | "INFO" | "WARNING" | "ERROR"
logger = get_logger(__name__)
```
<Warning>
**Call `setup_logging(level="INFO")` once at application startup.** Without it, Semantica falls back to Python's root logger, which may be silent or misconfigured. Call it before importing other Semantica modules to capture initialization messages.
</Warning>
@log_execution_time
def expensive_step(data):
...
# Logs: "expensive_step completed in 2.34s"
```
<Tip>
**`@log_execution_time` is the performance decorator.** Apply it to any function to automatically log its name, execution time, and success/failure. `log_performance` is a lower-level function for logging metrics you've already collected: it is not a decorator.
</Tip>
<Tip>
**Progress bars follow your terminal.** Console progress is written only when
stdout is an interactive terminal (or a Jupyter notebook), so piping or
redirecting output no longer fills logs with progress bars and escape
sequences. Set `SEMANTICA_DISABLE_PROGRESS` to silence progress even in a
terminal, or `SEMANTICA_FORCE_PROGRESS` to keep it when stdout is redirected.
`SEMANTICA_DISABLE_PROGRESS` wins if both are set.
</Tip>
Validation
from semantica.utils import validate_entity, validate_config, ValidationError
# validate_entity returns (is_valid, error_message)
is_valid, error = validate_entity({"id": "1", "type": "PERSON", "text": "Alice"})
if not is_valid:
raise ValidationError(error)
# validate_config returns (is_valid, error_message)
is_valid, error = validate_config(config, required_keys=["model", "provider"])
if not is_valid:
print(f"Invalid config: {error}")
| Function | Description | Returns |
|---|---|---|
validate_entity(data) |
Check entity dict has required fields (id, text, type) and correct types |
Tuple[bool, Optional[str]] |
validate_config(cfg, required_keys=None) |
Check configuration dict; optionally enforce required keys | Tuple[bool, Optional[str]] |
Progress Tracking
from semantica.utils import track_progress
# Wraps any iterable: auto-detects console vs Jupyter
for item in track_progress(items, desc="Processing documents"):
process(item)
Supports:
- Console: tqdm progress bar with ETA
- Jupyter: notebook-compatible widget (auto-detected)
- File: write progress to a log file
Helper Functions
from semantica.utils import clean_text, hash_data, safe_filename
# Normalize whitespace and strip control characters
clean = clean_text(" Hello World ") # -> "Hello World"
# Deterministic SHA-256 hash of a string, bytes, or dict
uid = hash_data({"key": "value"}) # -> hex digest string
# Sanitize a string for use as a filename
fname = safe_filename("My File?.txt") # -> "My_File.txt"
Nested Dict Utilities
Helper functions for deep configuration access: used extensively inside Config and ConfigManager:
from semantica.utils import get_nested_value, set_nested_value, merge_dicts
config = {
"processing": {"batch_size": 32, "max_workers": 4},
"llm": {"provider": "groq", "model": "llama-3.3-70b-versatile"},
}
# Dot-notation read: returns default if key path is absent
batch = get_nested_value(config, "processing.batch_size", default=16)
# -> 32
# Dot-notation write
set_nested_value(config, "processing.batch_size", 64)
# Deep merge: nested keys are merged recursively (deep=True by default)
base = {"a": {"x": 1, "y": 2}, "b": 3}
overrides = {"a": {"y": 99, "z": 4}, "c": 5}
merged = merge_dicts(base, overrides)
# -> {"a": {"x": 1, "y": 99, "z": 4}, "b": 3, "c": 5}
Exception Hierarchy
from semantica.utils import SemanticaError, ValidationError, ProcessingError
try:
run_pipeline(data)
except ValidationError as e:
# Input data did not pass schema validation
logger.error("Validation failed: %s", e.message)
except ProcessingError as e:
# Failure during extraction or graph construction
logger.error("Processing failed at stage %s: %s", e.stage, e)
except SemanticaError as e:
# Catch-all for all Semantica framework errors
logger.error("Framework error: %s", e)
| Exception | When Raised | Key Attributes |
|---|---|---|
SemanticaError |
Base class: all framework errors inherit from this | .message, .context, .error_code |
ValidationError |
Input data failed schema or type validation | .field, .value, .constraint |
ProcessingError |
Failure during extraction, graph build, or pipeline step | .stage, .input_data, .output_data |
ConfigurationError |
Configuration key missing or wrong type | .config_key, .config_value, .expected_type |
QualityError |
Data quality score fell below threshold | .quality_score, .threshold, .metrics |
File Utilities
from semantica.utils import read_json_file
# Read and parse a JSON file: raises FileNotFoundError or json.JSONDecodeError on failure
config = read_json_file("config.json")