fraiseql-confiture 0.3.4__cp311-cp311-win_amd64.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.
Files changed (119) hide show
  1. confiture/__init__.py +48 -0
  2. confiture/_core.cp311-win_amd64.pyd +0 -0
  3. confiture/cli/__init__.py +0 -0
  4. confiture/cli/dry_run.py +116 -0
  5. confiture/cli/lint_formatter.py +193 -0
  6. confiture/cli/main.py +1656 -0
  7. confiture/config/__init__.py +0 -0
  8. confiture/config/environment.py +263 -0
  9. confiture/core/__init__.py +51 -0
  10. confiture/core/anonymization/__init__.py +0 -0
  11. confiture/core/anonymization/audit.py +485 -0
  12. confiture/core/anonymization/benchmarking.py +372 -0
  13. confiture/core/anonymization/breach_notification.py +652 -0
  14. confiture/core/anonymization/compliance.py +617 -0
  15. confiture/core/anonymization/composer.py +298 -0
  16. confiture/core/anonymization/data_subject_rights.py +669 -0
  17. confiture/core/anonymization/factory.py +319 -0
  18. confiture/core/anonymization/governance.py +737 -0
  19. confiture/core/anonymization/performance.py +1092 -0
  20. confiture/core/anonymization/profile.py +284 -0
  21. confiture/core/anonymization/registry.py +195 -0
  22. confiture/core/anonymization/security/kms_manager.py +547 -0
  23. confiture/core/anonymization/security/lineage.py +888 -0
  24. confiture/core/anonymization/security/token_store.py +686 -0
  25. confiture/core/anonymization/strategies/__init__.py +41 -0
  26. confiture/core/anonymization/strategies/address.py +359 -0
  27. confiture/core/anonymization/strategies/credit_card.py +374 -0
  28. confiture/core/anonymization/strategies/custom.py +161 -0
  29. confiture/core/anonymization/strategies/date.py +218 -0
  30. confiture/core/anonymization/strategies/differential_privacy.py +398 -0
  31. confiture/core/anonymization/strategies/email.py +141 -0
  32. confiture/core/anonymization/strategies/format_preserving_encryption.py +310 -0
  33. confiture/core/anonymization/strategies/hash.py +150 -0
  34. confiture/core/anonymization/strategies/ip_address.py +235 -0
  35. confiture/core/anonymization/strategies/masking_retention.py +252 -0
  36. confiture/core/anonymization/strategies/name.py +298 -0
  37. confiture/core/anonymization/strategies/phone.py +119 -0
  38. confiture/core/anonymization/strategies/preserve.py +85 -0
  39. confiture/core/anonymization/strategies/redact.py +101 -0
  40. confiture/core/anonymization/strategies/salted_hashing.py +322 -0
  41. confiture/core/anonymization/strategies/text_redaction.py +183 -0
  42. confiture/core/anonymization/strategies/tokenization.py +334 -0
  43. confiture/core/anonymization/strategy.py +241 -0
  44. confiture/core/anonymization/syncer_audit.py +357 -0
  45. confiture/core/blue_green.py +683 -0
  46. confiture/core/builder.py +500 -0
  47. confiture/core/checksum.py +358 -0
  48. confiture/core/connection.py +132 -0
  49. confiture/core/differ.py +522 -0
  50. confiture/core/drift.py +564 -0
  51. confiture/core/dry_run.py +182 -0
  52. confiture/core/health.py +313 -0
  53. confiture/core/hooks/__init__.py +87 -0
  54. confiture/core/hooks/base.py +232 -0
  55. confiture/core/hooks/context.py +146 -0
  56. confiture/core/hooks/execution_strategies.py +57 -0
  57. confiture/core/hooks/observability.py +220 -0
  58. confiture/core/hooks/phases.py +53 -0
  59. confiture/core/hooks/registry.py +295 -0
  60. confiture/core/large_tables.py +775 -0
  61. confiture/core/linting/__init__.py +70 -0
  62. confiture/core/linting/composer.py +192 -0
  63. confiture/core/linting/libraries/__init__.py +17 -0
  64. confiture/core/linting/libraries/gdpr.py +168 -0
  65. confiture/core/linting/libraries/general.py +184 -0
  66. confiture/core/linting/libraries/hipaa.py +144 -0
  67. confiture/core/linting/libraries/pci_dss.py +104 -0
  68. confiture/core/linting/libraries/sox.py +120 -0
  69. confiture/core/linting/schema_linter.py +491 -0
  70. confiture/core/linting/versioning.py +151 -0
  71. confiture/core/locking.py +389 -0
  72. confiture/core/migration_generator.py +298 -0
  73. confiture/core/migrator.py +793 -0
  74. confiture/core/observability/__init__.py +44 -0
  75. confiture/core/observability/audit.py +323 -0
  76. confiture/core/observability/logging.py +187 -0
  77. confiture/core/observability/metrics.py +174 -0
  78. confiture/core/observability/tracing.py +192 -0
  79. confiture/core/pg_version.py +418 -0
  80. confiture/core/pool.py +406 -0
  81. confiture/core/risk/__init__.py +39 -0
  82. confiture/core/risk/predictor.py +188 -0
  83. confiture/core/risk/scoring.py +248 -0
  84. confiture/core/rollback_generator.py +388 -0
  85. confiture/core/schema_analyzer.py +769 -0
  86. confiture/core/schema_to_schema.py +590 -0
  87. confiture/core/security/__init__.py +32 -0
  88. confiture/core/security/logging.py +201 -0
  89. confiture/core/security/validation.py +416 -0
  90. confiture/core/signals.py +371 -0
  91. confiture/core/syncer.py +540 -0
  92. confiture/exceptions.py +192 -0
  93. confiture/integrations/__init__.py +0 -0
  94. confiture/models/__init__.py +0 -0
  95. confiture/models/lint.py +193 -0
  96. confiture/models/migration.py +180 -0
  97. confiture/models/schema.py +203 -0
  98. confiture/scenarios/__init__.py +36 -0
  99. confiture/scenarios/compliance.py +586 -0
  100. confiture/scenarios/ecommerce.py +199 -0
  101. confiture/scenarios/financial.py +253 -0
  102. confiture/scenarios/healthcare.py +315 -0
  103. confiture/scenarios/multi_tenant.py +340 -0
  104. confiture/scenarios/saas.py +295 -0
  105. confiture/testing/FRAMEWORK_API.md +722 -0
  106. confiture/testing/__init__.py +38 -0
  107. confiture/testing/fixtures/__init__.py +11 -0
  108. confiture/testing/fixtures/data_validator.py +229 -0
  109. confiture/testing/fixtures/migration_runner.py +167 -0
  110. confiture/testing/fixtures/schema_snapshotter.py +352 -0
  111. confiture/testing/frameworks/__init__.py +10 -0
  112. confiture/testing/frameworks/mutation.py +587 -0
  113. confiture/testing/frameworks/performance.py +479 -0
  114. confiture/testing/utils/__init__.py +0 -0
  115. fraiseql_confiture-0.3.4.dist-info/METADATA +438 -0
  116. fraiseql_confiture-0.3.4.dist-info/RECORD +119 -0
  117. fraiseql_confiture-0.3.4.dist-info/WHEEL +4 -0
  118. fraiseql_confiture-0.3.4.dist-info/entry_points.txt +2 -0
  119. fraiseql_confiture-0.3.4.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,174 @@
1
+ """Prometheus metrics for migrations.
2
+
3
+ Provides optional metrics integration for migration monitoring.
4
+ """
5
+
6
+ import logging
7
+ from dataclasses import dataclass
8
+ from typing import Any
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ @dataclass
14
+ class MetricsConfig:
15
+ """Configuration for Prometheus metrics."""
16
+
17
+ enabled: bool = False
18
+ port: int = 9090
19
+ path: str = "/metrics"
20
+
21
+
22
+ class MigrationMetrics:
23
+ """Prometheus metrics for migrations.
24
+
25
+ Exposes metrics when prometheus_client is installed:
26
+ - confiture_migrations_total (counter)
27
+ - confiture_migration_duration_seconds (histogram)
28
+ - confiture_migration_errors_total (counter)
29
+ - confiture_migration_last_success_timestamp (gauge)
30
+
31
+ Example:
32
+ >>> metrics = MigrationMetrics(MetricsConfig(enabled=True))
33
+ >>> metrics.start_server()
34
+ >>> metrics.record_migration("001", "create_users", 2.5, success=True)
35
+ """
36
+
37
+ def __init__(self, config: MetricsConfig):
38
+ """Initialize migration metrics.
39
+
40
+ Args:
41
+ config: Metrics configuration
42
+ """
43
+ self.config = config
44
+ self._registry: Any = None
45
+ self._migrations_total: Any = None
46
+ self._migration_duration: Any = None
47
+ self._migration_errors: Any = None
48
+ self._last_success: Any = None
49
+ self._initialized = False
50
+
51
+ if config.enabled:
52
+ self._initialize_metrics()
53
+
54
+ def _initialize_metrics(self) -> None:
55
+ """Initialize Prometheus metrics."""
56
+ try:
57
+ from prometheus_client import REGISTRY, Counter, Gauge, Histogram
58
+
59
+ self._registry = REGISTRY
60
+
61
+ # Define metrics
62
+ self._migrations_total = Counter(
63
+ "confiture_migrations_total",
64
+ "Total number of migrations executed",
65
+ ["version", "name", "status"],
66
+ registry=self._registry,
67
+ )
68
+
69
+ self._migration_duration = Histogram(
70
+ "confiture_migration_duration_seconds",
71
+ "Migration execution duration",
72
+ ["version"],
73
+ buckets=(0.1, 0.5, 1, 2, 5, 10, 30, 60, 120, 300),
74
+ registry=self._registry,
75
+ )
76
+
77
+ self._migration_errors = Counter(
78
+ "confiture_migration_errors_total",
79
+ "Total number of migration errors",
80
+ ["version", "error_type"],
81
+ registry=self._registry,
82
+ )
83
+
84
+ self._last_success = Gauge(
85
+ "confiture_migration_last_success_timestamp",
86
+ "Timestamp of last successful migration",
87
+ registry=self._registry,
88
+ )
89
+
90
+ self._initialized = True
91
+ logger.info("Prometheus metrics initialized")
92
+
93
+ except ImportError:
94
+ logger.warning(
95
+ "prometheus_client not installed. Install with: "
96
+ "pip install confiture[observability]"
97
+ )
98
+ self.config.enabled = False
99
+
100
+ @property
101
+ def is_enabled(self) -> bool:
102
+ """Check if metrics are enabled and initialized."""
103
+ return self.config.enabled and self._initialized
104
+
105
+ def start_server(self) -> None:
106
+ """Start Prometheus metrics HTTP server."""
107
+ if not self.is_enabled:
108
+ return
109
+
110
+ try:
111
+ from prometheus_client import start_http_server
112
+
113
+ start_http_server(self.config.port)
114
+ logger.info(f"Prometheus metrics server started on port {self.config.port}")
115
+
116
+ except Exception as e:
117
+ logger.error(f"Failed to start metrics server: {e}")
118
+
119
+ def record_migration(
120
+ self,
121
+ version: str,
122
+ name: str,
123
+ duration_seconds: float,
124
+ success: bool,
125
+ error: Exception | None = None,
126
+ ) -> None:
127
+ """Record migration execution metrics.
128
+
129
+ Args:
130
+ version: Migration version
131
+ name: Migration name
132
+ duration_seconds: Execution duration in seconds
133
+ success: Whether migration succeeded
134
+ error: Exception if failed (optional)
135
+ """
136
+ if not self.is_enabled:
137
+ return
138
+
139
+ import time
140
+
141
+ status = "success" if success else "error"
142
+ self._migrations_total.labels(version=version, name=name, status=status).inc()
143
+ self._migration_duration.labels(version=version).observe(duration_seconds)
144
+
145
+ if success:
146
+ self._last_success.set(time.time())
147
+ elif error:
148
+ error_type = type(error).__name__
149
+ self._migration_errors.labels(version=version, error_type=error_type).inc()
150
+
151
+ def record_error(self, version: str, error: Exception) -> None:
152
+ """Record a migration error.
153
+
154
+ Args:
155
+ version: Migration version
156
+ error: Exception that occurred
157
+ """
158
+ if not self.is_enabled:
159
+ return
160
+
161
+ error_type = type(error).__name__
162
+ self._migration_errors.labels(version=version, error_type=error_type).inc()
163
+
164
+
165
+ def create_metrics(config: MetricsConfig | None = None) -> MigrationMetrics:
166
+ """Factory function to create metrics.
167
+
168
+ Args:
169
+ config: Metrics configuration (optional)
170
+
171
+ Returns:
172
+ Configured MigrationMetrics
173
+ """
174
+ return MigrationMetrics(config or MetricsConfig())
@@ -0,0 +1,192 @@
1
+ """OpenTelemetry tracing for migrations.
2
+
3
+ Provides optional tracing integration for migration execution.
4
+ """
5
+
6
+ import logging
7
+ from collections.abc import Generator
8
+ from contextlib import contextmanager
9
+ from dataclasses import dataclass
10
+ from typing import Any
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ @dataclass
16
+ class TracingConfig:
17
+ """Configuration for OpenTelemetry tracing."""
18
+
19
+ enabled: bool = False
20
+ service_name: str = "confiture"
21
+ endpoint: str | None = None # OTLP endpoint
22
+ sample_rate: float = 1.0
23
+
24
+
25
+ class MigrationTracer:
26
+ """OpenTelemetry tracer for migrations.
27
+
28
+ Provides tracing spans for migration operations when OpenTelemetry
29
+ is installed and configured.
30
+
31
+ Example:
32
+ >>> tracer = MigrationTracer(TracingConfig(enabled=True))
33
+ >>> with tracer.span("migration.apply", migration_id="001"):
34
+ ... # Migration code
35
+ ... pass
36
+ """
37
+
38
+ def __init__(self, config: TracingConfig):
39
+ """Initialize migration tracer.
40
+
41
+ Args:
42
+ config: Tracing configuration
43
+ """
44
+ self.config = config
45
+ self._tracer: Any = None
46
+ self._initialized = False
47
+
48
+ if config.enabled:
49
+ self._initialize_tracer()
50
+
51
+ def _initialize_tracer(self) -> None:
52
+ """Initialize OpenTelemetry tracer."""
53
+ try:
54
+ from opentelemetry import trace
55
+ from opentelemetry.sdk.resources import Resource
56
+ from opentelemetry.sdk.trace import TracerProvider
57
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
58
+
59
+ # Create resource
60
+ resource = Resource.create(
61
+ {
62
+ "service.name": self.config.service_name,
63
+ "service.version": "0.5.0",
64
+ }
65
+ )
66
+
67
+ # Create provider
68
+ provider = TracerProvider(resource=resource)
69
+
70
+ # Add exporter if endpoint configured
71
+ if self.config.endpoint:
72
+ try:
73
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
74
+ OTLPSpanExporter,
75
+ )
76
+
77
+ exporter = OTLPSpanExporter(endpoint=self.config.endpoint)
78
+ provider.add_span_processor(BatchSpanProcessor(exporter))
79
+ except ImportError:
80
+ logger.warning(
81
+ "OTLP exporter not installed. Install with: "
82
+ "pip install opentelemetry-exporter-otlp"
83
+ )
84
+
85
+ trace.set_tracer_provider(provider)
86
+ self._tracer = trace.get_tracer("confiture")
87
+ self._initialized = True
88
+
89
+ logger.info("OpenTelemetry tracing initialized")
90
+
91
+ except ImportError:
92
+ logger.warning(
93
+ "OpenTelemetry not installed. Install with: pip install confiture[observability]"
94
+ )
95
+ self.config.enabled = False
96
+
97
+ @property
98
+ def is_enabled(self) -> bool:
99
+ """Check if tracing is enabled and initialized."""
100
+ return self.config.enabled and self._initialized
101
+
102
+ @contextmanager
103
+ def span(
104
+ self,
105
+ name: str,
106
+ **attributes: Any,
107
+ ) -> Generator[Any, None, None]:
108
+ """Create a tracing span.
109
+
110
+ Args:
111
+ name: Span name
112
+ **attributes: Span attributes
113
+
114
+ Yields:
115
+ Span context (or None if disabled)
116
+ """
117
+ if not self.is_enabled or self._tracer is None:
118
+ yield None
119
+ return
120
+
121
+ with self._tracer.start_as_current_span(name) as span:
122
+ for key, value in attributes.items():
123
+ span.set_attribute(key, str(value))
124
+ yield span
125
+
126
+ def record_migration_start(
127
+ self,
128
+ migration_version: str,
129
+ migration_name: str,
130
+ ) -> Any:
131
+ """Create a span for migration start.
132
+
133
+ Args:
134
+ migration_version: Migration version
135
+ migration_name: Migration name
136
+
137
+ Returns:
138
+ Span context manager
139
+ """
140
+ return self.span(
141
+ "confiture.migration.execute",
142
+ migration_version=migration_version,
143
+ migration_name=migration_name,
144
+ )
145
+
146
+ def record_error(self, span: Any, error: Exception) -> None:
147
+ """Record error on span.
148
+
149
+ Args:
150
+ span: Active span
151
+ error: Exception that occurred
152
+ """
153
+ if span is None or not self.is_enabled:
154
+ return
155
+
156
+ try:
157
+ from opentelemetry import trace
158
+
159
+ span.set_status(trace.Status(trace.StatusCode.ERROR))
160
+ span.record_exception(error)
161
+ except ImportError:
162
+ pass
163
+
164
+ def record_success(self, span: Any, duration_ms: int) -> None:
165
+ """Record successful completion on span.
166
+
167
+ Args:
168
+ span: Active span
169
+ duration_ms: Duration in milliseconds
170
+ """
171
+ if span is None or not self.is_enabled:
172
+ return
173
+
174
+ try:
175
+ from opentelemetry import trace
176
+
177
+ span.set_attribute("duration_ms", duration_ms)
178
+ span.set_status(trace.Status(trace.StatusCode.OK))
179
+ except ImportError:
180
+ pass
181
+
182
+
183
+ def create_tracer(config: TracingConfig | None = None) -> MigrationTracer:
184
+ """Factory function to create tracer.
185
+
186
+ Args:
187
+ config: Tracing configuration (optional)
188
+
189
+ Returns:
190
+ Configured MigrationTracer
191
+ """
192
+ return MigrationTracer(config or TracingConfig())