silver-diagnostics 0.1.0__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.
- silver_diagnostics-0.1.0/CHANGELOG.md +29 -0
- silver_diagnostics-0.1.0/CONTRIBUTING.md +114 -0
- silver_diagnostics-0.1.0/LICENSE +12 -0
- silver_diagnostics-0.1.0/MANIFEST.in +6 -0
- silver_diagnostics-0.1.0/PKG-INFO +294 -0
- silver_diagnostics-0.1.0/README.md +263 -0
- silver_diagnostics-0.1.0/pyproject.toml +46 -0
- silver_diagnostics-0.1.0/setup.cfg +4 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics/__init__.py +5 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics/dataset.py +76 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics/metrics.py +36 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics/models.py +16 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics/utils.py +8 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics.egg-info/PKG-INFO +294 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics.egg-info/SOURCES.txt +18 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics.egg-info/dependency_links.txt +1 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics.egg-info/requires.txt +8 -0
- silver_diagnostics-0.1.0/src/silver_diagnostics.egg-info/top_level.txt +1 -0
- silver_diagnostics-0.1.0/tests/__init__.py +1 -0
- silver_diagnostics-0.1.0/tests/test_diagnostics.py +279 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2024-08-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of silver-diagnostics
|
|
12
|
+
- Framework-neutral dataset diagnostics
|
|
13
|
+
- Training metrics validation and analysis
|
|
14
|
+
- Non-finite value detection (NaN, infinity)
|
|
15
|
+
- Exploding gradient detection and warnings
|
|
16
|
+
- Dataset structure validation (empty checks, length mismatches, width consistency)
|
|
17
|
+
- Comprehensive test suite covering edge cases
|
|
18
|
+
- Support for Python 3.8-3.12
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
- `diagnose_dataset()` - Validate datasets for common issues
|
|
22
|
+
- `diagnose_metrics()` - Check training metrics for problems
|
|
23
|
+
- `Diagnostic` dataclass - Structured diagnostic information
|
|
24
|
+
- `DiagnosticReport` - Collection of diagnostics with validity status
|
|
25
|
+
- Error severity levels (error, warning, info)
|
|
26
|
+
- Detailed diagnostic information with context
|
|
27
|
+
- Specialized gradient analysis for training stability
|
|
28
|
+
|
|
29
|
+
## [Unreleased]
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Contributing to silver-diagnostics
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to silver-diagnostics! This document provides guidelines and instructions for contributing to the project.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
- Python 3.8 or higher
|
|
9
|
+
- Git
|
|
10
|
+
- Virtual environment (recommended)
|
|
11
|
+
|
|
12
|
+
### Setting Up Development Environment
|
|
13
|
+
|
|
14
|
+
1. **Clone the repository**
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/adfgdartec/silver-diagnostics.git
|
|
17
|
+
cd silver-diagnostics
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. **Create a virtual environment**
|
|
21
|
+
```bash
|
|
22
|
+
python -m venv venv
|
|
23
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. **Install development dependencies**
|
|
27
|
+
```bash
|
|
28
|
+
pip install -e ".[dev]"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
4. **Run tests**
|
|
32
|
+
```bash
|
|
33
|
+
pytest
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
5. **Run tests with coverage**
|
|
37
|
+
```bash
|
|
38
|
+
pytest --cov=silver_diagnostics --cov-report=html
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Code Style
|
|
42
|
+
|
|
43
|
+
We use the following tools to maintain code quality:
|
|
44
|
+
|
|
45
|
+
- **flake8** for linting
|
|
46
|
+
- **mypy** for type checking
|
|
47
|
+
- **pytest** for testing
|
|
48
|
+
|
|
49
|
+
Run all quality checks:
|
|
50
|
+
```bash
|
|
51
|
+
flake8 src/ tests/
|
|
52
|
+
mypy src/
|
|
53
|
+
pytest
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Making Changes
|
|
57
|
+
|
|
58
|
+
1. **Create a branch**
|
|
59
|
+
```bash
|
|
60
|
+
git checkout -b feature/your-feature-name
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
2. **Make your changes**
|
|
64
|
+
- Write clear, descriptive commit messages
|
|
65
|
+
- Add tests for new functionality
|
|
66
|
+
- Update documentation as needed
|
|
67
|
+
|
|
68
|
+
3. **Run tests**
|
|
69
|
+
```bash
|
|
70
|
+
pytest
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
4. **Submit a pull request**
|
|
74
|
+
- Describe your changes clearly
|
|
75
|
+
- Reference any related issues
|
|
76
|
+
- Ensure all tests pass
|
|
77
|
+
|
|
78
|
+
## Testing
|
|
79
|
+
|
|
80
|
+
We aim for high test coverage. When adding new features:
|
|
81
|
+
|
|
82
|
+
- Write unit tests for new diagnostic functions
|
|
83
|
+
- Test edge cases (NaN, infinity, empty data, etc.)
|
|
84
|
+
- Ensure existing tests still pass
|
|
85
|
+
|
|
86
|
+
### Test Structure
|
|
87
|
+
```
|
|
88
|
+
tests/
|
|
89
|
+
├── __init__.py
|
|
90
|
+
└── test_diagnostics.py
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Documentation
|
|
94
|
+
|
|
95
|
+
- Update docstrings for any modified functions
|
|
96
|
+
- Add examples for new diagnostic rules
|
|
97
|
+
- Update README.md if user-facing changes are made
|
|
98
|
+
|
|
99
|
+
## Release Process
|
|
100
|
+
|
|
101
|
+
Releases are managed by maintainers:
|
|
102
|
+
|
|
103
|
+
1. Update version in `pyproject.toml`
|
|
104
|
+
2. Update `CHANGELOG.md`
|
|
105
|
+
3. Create a GitHub release
|
|
106
|
+
4. Package will be automatically published to PyPI
|
|
107
|
+
|
|
108
|
+
## Questions?
|
|
109
|
+
|
|
110
|
+
Feel free to open an issue for questions or discussions about contributions.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
By contributing, you agree that your contributions will be licensed under the Apache-2.0 License.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
|
|
4
|
+
Copyright 2026 Silver Contributors
|
|
5
|
+
|
|
6
|
+
Licensed under the Apache License, Version 2.0. You may obtain a copy of the
|
|
7
|
+
License at https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
10
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
11
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
12
|
+
specific language governing permissions and limitations under the License.
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: silver-diagnostics
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Framework-neutral ML data and training diagnostics for Silver.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Project-URL: Homepage, https://github.com/adfgdartec/silver-diagnostics
|
|
7
|
+
Project-URL: Repository, https://github.com/adfgdartec/silver-diagnostics
|
|
8
|
+
Project-URL: Issues, https://github.com/adfgdartec/silver-diagnostics/issues
|
|
9
|
+
Keywords: machine-learning,diagnostics,debugging,data-quality,python
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: flake8>=6.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: build>=0.10.0; extra == "dev"
|
|
29
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# silver-diagnostics
|
|
33
|
+
|
|
34
|
+
[](https://www.python.org/downloads/)
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
[](tests/)
|
|
37
|
+
[](https://flake8.pycqa.org/)
|
|
38
|
+
|
|
39
|
+
Framework-neutral ML data and training diagnostics for Silver. A Python package designed for ML researchers who need robust data validation and training stability checks across different frameworks.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install silver-diagnostics
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from silver_diagnostics import diagnose_dataset, diagnose_metrics
|
|
51
|
+
|
|
52
|
+
# Diagnose dataset issues
|
|
53
|
+
features = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
|
|
54
|
+
labels = [0.0, 1.0, 0.0]
|
|
55
|
+
|
|
56
|
+
report = diagnose_dataset(features, labels)
|
|
57
|
+
if not report.valid:
|
|
58
|
+
print("Dataset issues found:")
|
|
59
|
+
for diagnostic in report.diagnostics:
|
|
60
|
+
print(f" [{diagnostic.severity}] {diagnostic.message}")
|
|
61
|
+
|
|
62
|
+
# Diagnose metrics issues
|
|
63
|
+
metrics = {"loss": 0.5, "accuracy": 0.9, "gradient_norm": 1e6}
|
|
64
|
+
report = diagnose_metrics(metrics)
|
|
65
|
+
for diagnostic in report.diagnostics:
|
|
66
|
+
print(f"[{diagnostic.severity}] {diagnostic.message}")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Features
|
|
70
|
+
|
|
71
|
+
- **Dataset Validation**: Comprehensive checks for empty data, length mismatches, and structural issues
|
|
72
|
+
- **Non-Finite Detection**: Automatic detection of NaN and infinity values in features and labels
|
|
73
|
+
- **Metrics Diagnostics**: Training metrics validation for numerical stability
|
|
74
|
+
- **Exploding Gradient Detection**: Specialized checks for gradient explosion during training
|
|
75
|
+
- **Framework-Agnostic**: Works with PyTorch, TensorFlow, JAX, or any numeric data
|
|
76
|
+
- **Detailed Reporting**: Structured diagnostic information with severity levels and context
|
|
77
|
+
- **Type Safety**: Full type hints for better IDE support and fewer bugs
|
|
78
|
+
|
|
79
|
+
## Use Cases
|
|
80
|
+
|
|
81
|
+
### Training Pipeline Validation
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from silver_diagnostics import diagnose_dataset, diagnose_metrics
|
|
85
|
+
import torch
|
|
86
|
+
|
|
87
|
+
# Validate training data before training
|
|
88
|
+
train_features = torch.randn(1000, 10).numpy()
|
|
89
|
+
train_labels = torch.randint(0, 2, (1000,)).numpy()
|
|
90
|
+
|
|
91
|
+
report = diagnose_dataset(train_features.tolist(), train_labels.tolist())
|
|
92
|
+
if not report.valid:
|
|
93
|
+
print("Cannot train with invalid dataset:")
|
|
94
|
+
for diagnostic in report.diagnostics:
|
|
95
|
+
print(f" {diagnostic.code}: {diagnostic.message}")
|
|
96
|
+
else:
|
|
97
|
+
print("Dataset is valid for training")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Training Stability Monitoring
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from silver_diagnostics import diagnose_metrics
|
|
104
|
+
|
|
105
|
+
# Monitor training metrics for stability
|
|
106
|
+
def check_training_stability(metrics):
|
|
107
|
+
report = diagnose_metrics(metrics)
|
|
108
|
+
|
|
109
|
+
# Check for errors
|
|
110
|
+
errors = [d for d in report.diagnostics if d.severity == "error"]
|
|
111
|
+
if errors:
|
|
112
|
+
print("Training stability issues:")
|
|
113
|
+
for error in errors:
|
|
114
|
+
print(f" {error.code}: {error.message}")
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
# Check for warnings
|
|
118
|
+
warnings = [d for d in report.diagnostics if d.severity == "warning"]
|
|
119
|
+
if warnings:
|
|
120
|
+
print("Training stability warnings:")
|
|
121
|
+
for warning in warnings:
|
|
122
|
+
print(f" {warning.code}: {warning.message}")
|
|
123
|
+
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
# During training loop
|
|
127
|
+
for epoch in range(10):
|
|
128
|
+
loss = train_epoch()
|
|
129
|
+
metrics = {
|
|
130
|
+
"loss": loss,
|
|
131
|
+
"gradient_norm": compute_gradient_norm(),
|
|
132
|
+
"accuracy": evaluate()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if not check_training_stability(metrics):
|
|
136
|
+
print("Training unstable - stopping")
|
|
137
|
+
break
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Data Quality Assurance
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from silver_diagnostics import diagnose_dataset
|
|
144
|
+
|
|
145
|
+
def validate_ml_pipeline_data(X_train, y_train, X_val, y_val):
|
|
146
|
+
"""Validate all datasets in ML pipeline"""
|
|
147
|
+
datasets = {
|
|
148
|
+
"training": (X_train, y_train),
|
|
149
|
+
"validation": (X_val, y_val)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
all_valid = True
|
|
153
|
+
for name, (features, labels) in datasets.items():
|
|
154
|
+
report = diagnose_dataset(features.tolist(), labels.tolist())
|
|
155
|
+
|
|
156
|
+
print(f"\n{name} dataset:")
|
|
157
|
+
if report.valid:
|
|
158
|
+
print(f" ✓ Valid ({len(features)} samples)")
|
|
159
|
+
else:
|
|
160
|
+
print(f" ✗ Invalid")
|
|
161
|
+
for diagnostic in report.diagnostics:
|
|
162
|
+
print(f" {diagnostic.message}")
|
|
163
|
+
all_valid = False
|
|
164
|
+
|
|
165
|
+
return all_valid
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Framework Integration
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from silver_diagnostics import diagnose_dataset, diagnose_metrics
|
|
172
|
+
import tensorflow as tf
|
|
173
|
+
import torch
|
|
174
|
+
|
|
175
|
+
# Works with TensorFlow tensors
|
|
176
|
+
tf_features = tf.random.normal((100, 10))
|
|
177
|
+
tf_labels = tf.random.uniform((100,), maxval=2, dtype=tf.int32)
|
|
178
|
+
|
|
179
|
+
report = diagnose_dataset(
|
|
180
|
+
tf_features.numpy().tolist(),
|
|
181
|
+
tf_labels.numpy().tolist()
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Works with PyTorch tensors
|
|
185
|
+
torch_features = torch.randn(100, 10)
|
|
186
|
+
torch_labels = torch.randint(0, 2, (100,))
|
|
187
|
+
|
|
188
|
+
report = diagnose_dataset(
|
|
189
|
+
torch_features.tolist(),
|
|
190
|
+
torch_labels.tolist()
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Advanced Usage
|
|
195
|
+
|
|
196
|
+
### Custom Diagnostic Processing
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from silver_diagnostics import diagnose_dataset, Diagnostic
|
|
200
|
+
|
|
201
|
+
def categorize_diagnostics(report):
|
|
202
|
+
"""Categorize diagnostics by type"""
|
|
203
|
+
categories = {
|
|
204
|
+
"structural": [],
|
|
205
|
+
"data_quality": [],
|
|
206
|
+
"numerical": []
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
for diagnostic in report.diagnostics:
|
|
210
|
+
if diagnostic.code in ["empty_dataset", "length_mismatch", "feature_width_mismatch"]:
|
|
211
|
+
categories["structural"].append(diagnostic)
|
|
212
|
+
elif diagnostic.code in ["non_finite_feature", "non_finite_label"]:
|
|
213
|
+
categories["numerical"].append(diagnostic)
|
|
214
|
+
else:
|
|
215
|
+
categories["data_quality"].append(diagnostic)
|
|
216
|
+
|
|
217
|
+
return categories
|
|
218
|
+
|
|
219
|
+
report = diagnose_dataset(features, labels)
|
|
220
|
+
categories = categorize_diagnostics(report)
|
|
221
|
+
|
|
222
|
+
for category, diagnostics in categories.items():
|
|
223
|
+
if diagnostics:
|
|
224
|
+
print(f"{category.upper()} ({len(diagnostics)}):")
|
|
225
|
+
for diag in diagnostics:
|
|
226
|
+
print(f" - {diag.message}")
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Batch Validation
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from silver_diagnostics import diagnose_dataset
|
|
233
|
+
|
|
234
|
+
def validate_multiple_datasets(dataset_dict):
|
|
235
|
+
"""Validate multiple datasets at once"""
|
|
236
|
+
results = {}
|
|
237
|
+
|
|
238
|
+
for name, (features, labels) in dataset_dict.items():
|
|
239
|
+
report = diagnose_dataset(features, labels)
|
|
240
|
+
results[name] = {
|
|
241
|
+
"valid": report.valid,
|
|
242
|
+
"error_count": sum(1 for d in report.diagnostics if d.severity == "error"),
|
|
243
|
+
"warning_count": sum(1 for d in report.diagnostics if d.severity == "warning"),
|
|
244
|
+
"diagnostics": report.diagnostics
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return results
|
|
248
|
+
|
|
249
|
+
datasets = {
|
|
250
|
+
"train": (X_train.tolist(), y_train.tolist()),
|
|
251
|
+
"val": (X_val.tolist(), y_val.tolist()),
|
|
252
|
+
"test": (X_test.tolist(), y_test.tolist())
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
validation_results = validate_multiple_datasets(datasets)
|
|
256
|
+
for name, result in validation_results.items():
|
|
257
|
+
status = "✓" if result["valid"] else "✗"
|
|
258
|
+
print(f"{status} {name}: {result['error_count']} errors, {result['warning_count']} warnings")
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Requirements
|
|
262
|
+
|
|
263
|
+
- Python 3.8+
|
|
264
|
+
|
|
265
|
+
## Development
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Install development dependencies
|
|
269
|
+
pip install -e ".[dev]"
|
|
270
|
+
|
|
271
|
+
# Run tests
|
|
272
|
+
pytest
|
|
273
|
+
|
|
274
|
+
# Run tests with coverage
|
|
275
|
+
pytest --cov=silver_diagnostics --cov-report=html
|
|
276
|
+
|
|
277
|
+
# Run linting
|
|
278
|
+
flake8 src/ tests/
|
|
279
|
+
mypy src/
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Contributing
|
|
283
|
+
|
|
284
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
285
|
+
|
|
286
|
+
## License
|
|
287
|
+
|
|
288
|
+
Apache-2.0 - see [LICENSE](LICENSE) file for details.
|
|
289
|
+
|
|
290
|
+
## Related Packages
|
|
291
|
+
|
|
292
|
+
- [silver-data](https://github.com/adfgdartec/silver-data) - Dataset handling
|
|
293
|
+
- [silver-run](https://github.com/adfgdartec/silver-run) - Training lifecycle
|
|
294
|
+
- [silver-adapters](https://github.com/adfgdartec/silver-adapters) - Framework adapters
|