silver-data 0.1.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.
- silver_data/__init__.py +19 -0
- silver_data/dataset.py +160 -0
- silver_data/models.py +35 -0
- silver_data-0.1.0.dist-info/METADATA +225 -0
- silver_data-0.1.0.dist-info/RECORD +8 -0
- silver_data-0.1.0.dist-info/WHEEL +5 -0
- silver_data-0.1.0.dist-info/licenses/LICENSE +12 -0
- silver_data-0.1.0.dist-info/top_level.txt +1 -0
silver_data/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .dataset import Dataset
|
|
2
|
+
from .models import (
|
|
3
|
+
DataRecord,
|
|
4
|
+
DatasetColumn,
|
|
5
|
+
DatasetReport,
|
|
6
|
+
DatasetSplit,
|
|
7
|
+
DatasetValidation,
|
|
8
|
+
Primitive,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"Dataset",
|
|
13
|
+
"DatasetColumn",
|
|
14
|
+
"DatasetReport",
|
|
15
|
+
"DatasetValidation",
|
|
16
|
+
"DatasetSplit",
|
|
17
|
+
"Primitive",
|
|
18
|
+
"DataRecord",
|
|
19
|
+
]
|
silver_data/dataset.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import hashlib
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any, List, Union
|
|
5
|
+
|
|
6
|
+
from .models import (
|
|
7
|
+
DataRecord,
|
|
8
|
+
DatasetColumn,
|
|
9
|
+
DatasetReport,
|
|
10
|
+
DatasetSplit,
|
|
11
|
+
DatasetValidation,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Dataset:
|
|
16
|
+
def __init__(self, name: str, rows: List[DataRecord]):
|
|
17
|
+
if not name.strip():
|
|
18
|
+
raise ValueError("Dataset name is required")
|
|
19
|
+
self.name = name
|
|
20
|
+
self._rows = [dict(row) for row in rows]
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def from_records(cls, name: str, rows: List[DataRecord]) -> "Dataset":
|
|
24
|
+
if len(rows) == 0:
|
|
25
|
+
raise ValueError("Dataset must contain at least one row")
|
|
26
|
+
return cls(name, [dict(row) for row in rows])
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_json(
|
|
30
|
+
cls, name: str, value: Union[List[DataRecord], DataRecord]
|
|
31
|
+
) -> "Dataset":
|
|
32
|
+
if isinstance(value, dict):
|
|
33
|
+
return cls.from_records(name, [value])
|
|
34
|
+
return cls.from_records(name, value)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_jsonl(cls, name: str, value: str) -> "Dataset":
|
|
38
|
+
lines = [line.strip() for line in value.strip().splitlines() if line.strip()]
|
|
39
|
+
records = []
|
|
40
|
+
for line in lines:
|
|
41
|
+
record = json.loads(line)
|
|
42
|
+
if not isinstance(record, dict) or isinstance(record, list):
|
|
43
|
+
raise ValueError("JSONL rows must be objects")
|
|
44
|
+
records.append(record)
|
|
45
|
+
return cls.from_records(name, records)
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_csv(cls, name: str, path: str) -> "Dataset":
|
|
49
|
+
try:
|
|
50
|
+
import pandas as pd
|
|
51
|
+
except ImportError:
|
|
52
|
+
pd = None
|
|
53
|
+
if pd is not None:
|
|
54
|
+
return cls.from_records(name, pd.read_csv(path).to_dict(orient="records"))
|
|
55
|
+
with open(path, newline="", encoding="utf-8") as stream:
|
|
56
|
+
return cls.from_records(name, list(csv.DictReader(stream)))
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def from_pandas(cls, name: str, df: Any) -> "Dataset":
|
|
60
|
+
if not hasattr(df, "to_dict"):
|
|
61
|
+
raise TypeError("from_pandas requires an object with to_dict")
|
|
62
|
+
return cls.from_records(name, df.to_dict(orient="records"))
|
|
63
|
+
|
|
64
|
+
def records(self) -> List[DataRecord]:
|
|
65
|
+
return [dict(row) for row in self._rows]
|
|
66
|
+
|
|
67
|
+
def columns(self) -> List[str]:
|
|
68
|
+
all_columns = set()
|
|
69
|
+
for row in self._rows:
|
|
70
|
+
all_columns.update(row.keys())
|
|
71
|
+
return sorted(all_columns)
|
|
72
|
+
|
|
73
|
+
def inspect(self) -> DatasetReport:
|
|
74
|
+
columns_report = []
|
|
75
|
+
for name in self.columns():
|
|
76
|
+
values = [row.get(name) for row in self._rows]
|
|
77
|
+
present = [value for value in values if value is not None]
|
|
78
|
+
if present:
|
|
79
|
+
types = {type(value).__name__ for value in present}
|
|
80
|
+
if len(types) == 1:
|
|
81
|
+
type_name = type(present[0]).__name__
|
|
82
|
+
value_type = {
|
|
83
|
+
"str": "string",
|
|
84
|
+
"int": "number",
|
|
85
|
+
"float": "number",
|
|
86
|
+
"bool": "boolean",
|
|
87
|
+
}.get(type_name, "mixed")
|
|
88
|
+
else:
|
|
89
|
+
value_type = "mixed"
|
|
90
|
+
else:
|
|
91
|
+
value_type = "null"
|
|
92
|
+
columns_report.append(
|
|
93
|
+
DatasetColumn(
|
|
94
|
+
name=name,
|
|
95
|
+
value_type=value_type,
|
|
96
|
+
missing=len(values) - len(present),
|
|
97
|
+
unique=len({json.dumps(value, sort_keys=True) for value in values}),
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
return DatasetReport(
|
|
101
|
+
name=self.name,
|
|
102
|
+
rows=len(self._rows),
|
|
103
|
+
columns=columns_report,
|
|
104
|
+
fingerprint=self.fingerprint(),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def validate(self) -> DatasetValidation:
|
|
108
|
+
errors = []
|
|
109
|
+
warnings = []
|
|
110
|
+
column_count = len(self.columns())
|
|
111
|
+
inconsistent_rows = [
|
|
112
|
+
index
|
|
113
|
+
for index, row in enumerate(self._rows)
|
|
114
|
+
if len(row.keys()) != column_count
|
|
115
|
+
]
|
|
116
|
+
if inconsistent_rows:
|
|
117
|
+
warnings.append(
|
|
118
|
+
f"Rows do not all contain the same columns: {inconsistent_rows[:5]}"
|
|
119
|
+
)
|
|
120
|
+
for column in self.inspect().columns:
|
|
121
|
+
if column.missing > 0:
|
|
122
|
+
warnings.append(f"{column.name} has {column.missing} missing values")
|
|
123
|
+
return DatasetValidation(
|
|
124
|
+
valid=len(errors) == 0, errors=errors, warnings=warnings
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def fingerprint(self) -> str:
|
|
128
|
+
data = json.dumps({"name": self.name, "rows": self._rows}, sort_keys=True)
|
|
129
|
+
return hashlib.md5(data.encode()).hexdigest()[:8]
|
|
130
|
+
|
|
131
|
+
def split(
|
|
132
|
+
self, train: float = 0.8, validation: float = 0.1, test: float = 0.1
|
|
133
|
+
) -> DatasetSplit:
|
|
134
|
+
if train < 0 or validation < 0 or test < 0:
|
|
135
|
+
raise ValueError("Dataset split ratios must be non-negative")
|
|
136
|
+
if abs(train + validation + test - 1.0) > 1e-9:
|
|
137
|
+
raise ValueError("Dataset split ratios must sum to 1")
|
|
138
|
+
train_end = int(len(self._rows) * train)
|
|
139
|
+
validation_end = train_end + int(len(self._rows) * validation)
|
|
140
|
+
return DatasetSplit(
|
|
141
|
+
train=Dataset._from_rows(f"{self.name}/train", self._rows[:train_end]),
|
|
142
|
+
validation=Dataset._from_rows(
|
|
143
|
+
f"{self.name}/validation", self._rows[train_end:validation_end]
|
|
144
|
+
),
|
|
145
|
+
test=Dataset._from_rows(f"{self.name}/test", self._rows[validation_end:]),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
@classmethod
|
|
149
|
+
def _from_rows(cls, name: str, rows: List[DataRecord]) -> "Dataset":
|
|
150
|
+
return cls(name, [dict(row) for row in rows])
|
|
151
|
+
|
|
152
|
+
def to_pandas(self) -> Any:
|
|
153
|
+
try:
|
|
154
|
+
import pandas as pd
|
|
155
|
+
except ImportError as error:
|
|
156
|
+
raise ImportError(
|
|
157
|
+
"Dataset.to_pandas() requires the optional 'pandas' dependency; "
|
|
158
|
+
"install silver-data[pandas]"
|
|
159
|
+
) from error
|
|
160
|
+
return pd.DataFrame(self._rows, columns=self.columns())
|
silver_data/models.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Dict, List, Literal, Union
|
|
3
|
+
|
|
4
|
+
Primitive = Union[str, int, float, bool, None]
|
|
5
|
+
DataRecord = Dict[str, Primitive]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class DatasetColumn:
|
|
10
|
+
name: str
|
|
11
|
+
value_type: Literal["string", "number", "boolean", "null", "mixed"]
|
|
12
|
+
missing: int
|
|
13
|
+
unique: int
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class DatasetReport:
|
|
18
|
+
name: str
|
|
19
|
+
rows: int
|
|
20
|
+
columns: List[DatasetColumn]
|
|
21
|
+
fingerprint: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class DatasetValidation:
|
|
26
|
+
valid: bool
|
|
27
|
+
errors: List[str]
|
|
28
|
+
warnings: List[str]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class DatasetSplit:
|
|
33
|
+
train: "Dataset"
|
|
34
|
+
validation: "Dataset"
|
|
35
|
+
test: "Dataset"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: silver-data
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Inspectable, deterministic dataset contracts and loaders for Silver.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Project-URL: Homepage, https://github.com/adfgdartec/silver-data
|
|
7
|
+
Project-URL: Repository, https://github.com/adfgdartec/silver-data
|
|
8
|
+
Project-URL: Issues, https://github.com/adfgdartec/silver-data/issues
|
|
9
|
+
Keywords: machine-learning,datasets,csv,data-validation,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: pandas
|
|
24
|
+
Requires-Dist: pandas>=1.0.0; extra == "pandas"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pandas>=1.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: flake8>=6.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: build>=0.10.0; extra == "dev"
|
|
32
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# silver-data
|
|
36
|
+
|
|
37
|
+
[](https://www.python.org/downloads/)
|
|
38
|
+
[](LICENSE)
|
|
39
|
+
[](tests/)
|
|
40
|
+
[](https://flake8.pycqa.org/)
|
|
41
|
+
|
|
42
|
+
Inspectable, deterministic dataset contracts and loaders for Silver. A Python package designed for ML researchers who need reliable dataset handling with built-in validation and reproducibility features.
|
|
43
|
+
|
|
44
|
+
The base install uses only the Python standard library for records, JSON, JSONL,
|
|
45
|
+
and CSV. Add pandas only when you need DataFrame conversion:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install 'silver-data[pandas]'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install silver-data
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from silver_data import Dataset
|
|
61
|
+
|
|
62
|
+
# Load from CSV file
|
|
63
|
+
dataset = Dataset.from_csv("my_data", "path/to/data.csv")
|
|
64
|
+
|
|
65
|
+
# Optional: load from pandas
|
|
66
|
+
import pandas as pd
|
|
67
|
+
df = pd.read_csv("path/to/data.csv")
|
|
68
|
+
dataset = Dataset.from_pandas("my_data", df)
|
|
69
|
+
|
|
70
|
+
# Inspect dataset
|
|
71
|
+
report = dataset.inspect()
|
|
72
|
+
print(f"Rows: {report.rows}, Columns: {len(report.columns)}")
|
|
73
|
+
for col in report.columns:
|
|
74
|
+
print(f" {col.name}: {col.value_type} ({col.unique} unique, {col.missing} missing)")
|
|
75
|
+
|
|
76
|
+
# Validate dataset
|
|
77
|
+
validation = dataset.validate()
|
|
78
|
+
if not validation.valid:
|
|
79
|
+
print("Errors:", validation.errors)
|
|
80
|
+
if validation.warnings:
|
|
81
|
+
print("Warnings:", validation.warnings)
|
|
82
|
+
|
|
83
|
+
# Split dataset for ML workflows
|
|
84
|
+
train, val, test = dataset.split(train=0.8, validation=0.1, test=0.1)
|
|
85
|
+
print(f"Train: {len(train.records())}, Val: {len(val.records())}, Test: {len(test.records())}")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Features
|
|
89
|
+
|
|
90
|
+
- **Multiple Data Sources**: Load from CSV, JSON, JSONL, and pandas DataFrames
|
|
91
|
+
- **Dataset Inspection**: Get detailed column statistics and metadata
|
|
92
|
+
- **Data Validation**: Automatic detection of missing values, inconsistent columns, and data quality issues
|
|
93
|
+
- **Deterministic Fingerprinting**: Generate unique identifiers for datasets to ensure reproducibility
|
|
94
|
+
- **Smart Splitting**: Train/validation/test splitting with customizable ratios
|
|
95
|
+
- **Immutable Design**: Safe data handling with copy-on-write semantics
|
|
96
|
+
- **Type Safety**: Full type hints for better IDE support and fewer bugs
|
|
97
|
+
|
|
98
|
+
## Use Cases
|
|
99
|
+
|
|
100
|
+
### ML Pipeline Integration
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from silver_data import Dataset
|
|
104
|
+
import pandas as pd
|
|
105
|
+
|
|
106
|
+
# Load and validate training data
|
|
107
|
+
df = pd.read_csv("train.csv")
|
|
108
|
+
dataset = Dataset.from_pandas("training", df)
|
|
109
|
+
|
|
110
|
+
# Ensure data quality before training
|
|
111
|
+
validation = dataset.validate()
|
|
112
|
+
if not validation.valid:
|
|
113
|
+
raise ValueError(f"Dataset validation failed: {validation.errors}")
|
|
114
|
+
|
|
115
|
+
# Split for cross-validation
|
|
116
|
+
train_split, val_split, test_split = dataset.split(train=0.7, validation=0.15, test=0.15)
|
|
117
|
+
|
|
118
|
+
# Use fingerprints for caching
|
|
119
|
+
cache_key = dataset.fingerprint()
|
|
120
|
+
print(f"Dataset fingerprint: {cache_key}")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Data Quality Monitoring
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from silver_data import Dataset
|
|
127
|
+
|
|
128
|
+
# Monitor data drift over time
|
|
129
|
+
dataset_v1 = Dataset.from_csv("data_v1", "data_2024_01.csv")
|
|
130
|
+
dataset_v2 = Dataset.from_csv("data_v2", "data_2024_02.csv")
|
|
131
|
+
|
|
132
|
+
if dataset_v1.fingerprint() != dataset_v2.fingerprint():
|
|
133
|
+
print("Dataset has changed - retrain models")
|
|
134
|
+
|
|
135
|
+
# Check for new data quality issues
|
|
136
|
+
report_v2 = dataset_v2.inspect()
|
|
137
|
+
for col in report_v2.columns:
|
|
138
|
+
if col.missing > len(dataset_v2.records()) * 0.1: # More than 10% missing
|
|
139
|
+
print(f"Warning: {col.name} has high missing rate: {col.missing}")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Experiment Reproducibility
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from silver_data import Dataset
|
|
146
|
+
|
|
147
|
+
# Ensure exact same data across experiments
|
|
148
|
+
dataset = Dataset.from_csv("experiment", "data.csv")
|
|
149
|
+
experiment_id = f"exp_{dataset.fingerprint()}"
|
|
150
|
+
|
|
151
|
+
# Log for reproducibility
|
|
152
|
+
print(f"Running experiment {experiment_id} with dataset fingerprint {dataset.fingerprint()}")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Advanced Usage
|
|
156
|
+
|
|
157
|
+
### Custom Data Loading
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from silver_data import Dataset
|
|
161
|
+
import json
|
|
162
|
+
|
|
163
|
+
# Load from custom JSON format
|
|
164
|
+
with open("custom_data.json") as f:
|
|
165
|
+
data = json.load(f)
|
|
166
|
+
dataset = Dataset.from_json("custom", data)
|
|
167
|
+
|
|
168
|
+
# Load from streaming JSONL
|
|
169
|
+
with open("streaming_data.jsonl") as f:
|
|
170
|
+
dataset = Dataset.from_jsonl("streaming", f.read())
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Data Type Analysis
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from silver_data import Dataset
|
|
177
|
+
|
|
178
|
+
dataset = Dataset.from_csv("analysis", "mixed_data.csv")
|
|
179
|
+
report = dataset.inspect()
|
|
180
|
+
|
|
181
|
+
# Analyze column types
|
|
182
|
+
string_cols = [c.name for c in report.columns if c.value_type == "string"]
|
|
183
|
+
numeric_cols = [c.name for c in report.columns if c.value_type == "number"]
|
|
184
|
+
mixed_cols = [c.name for c in report.columns if c.value_type == "mixed"]
|
|
185
|
+
|
|
186
|
+
print(f"String columns: {string_cols}")
|
|
187
|
+
print(f"Numeric columns: {numeric_cols}")
|
|
188
|
+
print(f"Mixed type columns: {mixed_cols}")
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Requirements
|
|
192
|
+
|
|
193
|
+
- Python 3.8+
|
|
194
|
+
- pandas 1.0+
|
|
195
|
+
|
|
196
|
+
## Development
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Install development dependencies
|
|
200
|
+
pip install -e ".[dev]"
|
|
201
|
+
|
|
202
|
+
# Run tests
|
|
203
|
+
pytest
|
|
204
|
+
|
|
205
|
+
# Run tests with coverage
|
|
206
|
+
pytest --cov=silver_data --cov-report=html
|
|
207
|
+
|
|
208
|
+
# Run linting
|
|
209
|
+
flake8 src/ tests/
|
|
210
|
+
mypy src/
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
Apache-2.0 - see [LICENSE](LICENSE) file for details.
|
|
220
|
+
|
|
221
|
+
## Related Packages
|
|
222
|
+
|
|
223
|
+
- [silver-run](https://github.com/adfgdartec/silver-run) - Training lifecycle management
|
|
224
|
+
- [silver-diagnostics](https://github.com/adfgdartec/silver-diagnostics) - ML diagnostics
|
|
225
|
+
- [silver-adapters](https://github.com/adfgdartec/silver-adapters) - Framework adapters
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
silver_data/__init__.py,sha256=xafu4vIPLaZ26ypIrmMyrzElSbkBb6ieG_KGEKGV6xA,315
|
|
2
|
+
silver_data/dataset.py,sha256=SIikl97ZpervJsT4PkWsf7H-P8gjphMOZN6emOvl-X4,5876
|
|
3
|
+
silver_data/models.py,sha256=EaxPmK8L-s3FMkwIir2xvtlA6xP-7zgRVM-KEB08hP4,683
|
|
4
|
+
silver_data-0.1.0.dist-info/licenses/LICENSE,sha256=9uEgZddcCAZ2jYIKny4rlbkQMZFhKRvSGbxctAg4wjI,517
|
|
5
|
+
silver_data-0.1.0.dist-info/METADATA,sha256=azOwbu62C6CwY9ptzl762I1jnOlKbKDtfKjXWFFUXYQ,6952
|
|
6
|
+
silver_data-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
7
|
+
silver_data-0.1.0.dist-info/top_level.txt,sha256=PlSkMomi6jHDrFFWnkgEeH_LAYiD7OWITwI4ckTVrkY,12
|
|
8
|
+
silver_data-0.1.0.dist-info/RECORD,,
|
|
@@ -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 @@
|
|
|
1
|
+
silver_data
|