scilineage 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.
- scilineage-0.1.0/.gitignore +10 -0
- scilineage-0.1.0/PKG-INFO +195 -0
- scilineage-0.1.0/README.md +153 -0
- scilineage-0.1.0/pyproject.toml +98 -0
- scilineage-0.1.0/src/scilineage/__init__.py +77 -0
- scilineage-0.1.0/src/scilineage/backend.py +29 -0
- scilineage-0.1.0/src/scilineage/core.py +610 -0
- scilineage-0.1.0/src/scilineage/hashing.py +212 -0
- scilineage-0.1.0/src/scilineage/inputs.py +241 -0
- scilineage-0.1.0/src/scilineage/lineage.py +175 -0
- scilineage-0.1.0/src/scilineage/py.typed +0 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scilineage
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lineage tracking for Python data pipelines
|
|
5
|
+
Project-URL: Documentation, https://github.com/example/scilineage#readme
|
|
6
|
+
Project-URL: Repository, https://github.com/example/scilineage
|
|
7
|
+
Project-URL: Issues, https://github.com/example/scilineage/issues
|
|
8
|
+
Author: SciStack Contributors
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: data-science,lineage,pipeline,provenance,reproducibility
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: canonicalhash>=0.1.0
|
|
25
|
+
Provides-Extra: all
|
|
26
|
+
Requires-Dist: numpy>=1.20; extra == 'all'
|
|
27
|
+
Requires-Dist: pandas>=1.3; extra == 'all'
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
33
|
+
Provides-Extra: docs
|
|
34
|
+
Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
|
|
35
|
+
Requires-Dist: mkdocs>=1.5; extra == 'docs'
|
|
36
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
|
|
37
|
+
Provides-Extra: numpy
|
|
38
|
+
Requires-Dist: numpy>=1.20; extra == 'numpy'
|
|
39
|
+
Provides-Extra: pandas
|
|
40
|
+
Requires-Dist: pandas>=1.3; extra == 'pandas'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# SciLineage
|
|
44
|
+
|
|
45
|
+
**Lineage tracking for Python data pipelines.**
|
|
46
|
+
|
|
47
|
+
SciLineage is a lightweight library for building data processing pipelines with automatic provenance tracking. It captures the full computational lineage of your results, enabling reproducibility and intelligent caching.
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- **Automatic Lineage Tracking**: Every computation captures its inputs and function, building a complete provenance graph
|
|
52
|
+
- **Input Classification**: Automatically distinguishes variable inputs from constants for accurate lineage
|
|
53
|
+
- **Pluggable Caching**: Register a backend via `configure_backend()` to enable cache lookups via lineage hashes
|
|
54
|
+
- **Lightweight**: Core dependency is only `canonicalhash`
|
|
55
|
+
- **Type Safe**: Full type hints throughout
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install scilineage
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
### Basic Usage
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from scilineage import lineage_fcn
|
|
69
|
+
|
|
70
|
+
@lineage_fcn
|
|
71
|
+
def process(data, factor):
|
|
72
|
+
return data * factor
|
|
73
|
+
|
|
74
|
+
# Call returns a LineageFcnResult, not the raw result
|
|
75
|
+
result = process([1, 2, 3], 2)
|
|
76
|
+
|
|
77
|
+
# Access the computed value
|
|
78
|
+
print(result.data) # [2, 4, 6]
|
|
79
|
+
|
|
80
|
+
# Access lineage information
|
|
81
|
+
print(result.invoked.inputs) # {'arg_0': [1, 2, 3], 'arg_1': 2}
|
|
82
|
+
print(result.invoked.fcn.fcn.__name__) # 'process'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Multi-Output Functions
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
@lineage_fcn(unpack_output=True)
|
|
89
|
+
def split_data(data):
|
|
90
|
+
mid = len(data) // 2
|
|
91
|
+
return data[:mid], data[mid:]
|
|
92
|
+
|
|
93
|
+
first, second = split_data([1, 2, 3, 4])
|
|
94
|
+
print(first.data) # [1, 2]
|
|
95
|
+
print(second.data) # [3, 4]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Chaining Computations
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
@lineage_fcn
|
|
102
|
+
def normalize(data):
|
|
103
|
+
max_val = max(data)
|
|
104
|
+
return [x / max_val for x in data]
|
|
105
|
+
|
|
106
|
+
@lineage_fcn
|
|
107
|
+
def scale(data, factor):
|
|
108
|
+
return [x * factor for x in data]
|
|
109
|
+
|
|
110
|
+
raw = [10, 20, 30, 40]
|
|
111
|
+
normalized = normalize(raw)
|
|
112
|
+
scaled = scale(normalized, 100)
|
|
113
|
+
|
|
114
|
+
print(scaled.data) # [25.0, 50.0, 75.0, 100.0]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Extracting Lineage
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from scilineage import extract_lineage, get_upstream_lineage
|
|
121
|
+
|
|
122
|
+
@lineage_fcn
|
|
123
|
+
def step1(x):
|
|
124
|
+
return x + 1
|
|
125
|
+
|
|
126
|
+
@lineage_fcn
|
|
127
|
+
def step2(x):
|
|
128
|
+
return x * 2
|
|
129
|
+
|
|
130
|
+
result = step2(step1(5))
|
|
131
|
+
|
|
132
|
+
lineage = extract_lineage(result)
|
|
133
|
+
print(lineage.function_name) # 'step2'
|
|
134
|
+
print(lineage.function_hash) # SHA-256 of function bytecode
|
|
135
|
+
|
|
136
|
+
chain = get_upstream_lineage(result)
|
|
137
|
+
for record in chain:
|
|
138
|
+
print(f"{record['function_name']}: inputs={record['inputs']}")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Manual Interventions
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from scilineage import manual
|
|
145
|
+
|
|
146
|
+
# Step outside the pipeline for a manual correction
|
|
147
|
+
edited_data = [1, 2, 3]
|
|
148
|
+
|
|
149
|
+
# Re-enter the pipeline — the intervention is documented in lineage
|
|
150
|
+
corrected = manual(
|
|
151
|
+
edited_data,
|
|
152
|
+
label="outlier_removal",
|
|
153
|
+
reason="amplitude < 0.1 in trial 3 is sensor artifact",
|
|
154
|
+
)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## API Reference
|
|
158
|
+
|
|
159
|
+
### `@lineage_fcn(unpack_output=False, unwrap=True, generates_file=False)`
|
|
160
|
+
|
|
161
|
+
Decorator to convert a function into a `LineageFcn`.
|
|
162
|
+
|
|
163
|
+
- `unpack_output`: Whether to unpack a tuple return into separate `LineageFcnResult`s
|
|
164
|
+
- `unwrap`: If True, automatically unwrap `LineageFcnResult` inputs to their raw data
|
|
165
|
+
- `generates_file`: If True, marks the function as producing files as side effects
|
|
166
|
+
|
|
167
|
+
### `LineageFcnResult`
|
|
168
|
+
|
|
169
|
+
Wrapper around computed values that carries lineage.
|
|
170
|
+
|
|
171
|
+
- `.data`: The actual computed value
|
|
172
|
+
- `.invoked`: The `LineageFcnInvocation` that produced this
|
|
173
|
+
- `.hash`: Unique hash based on computation lineage
|
|
174
|
+
- `.output_num`: Index for multi-output functions
|
|
175
|
+
|
|
176
|
+
### `LineageFcnInvocation`
|
|
177
|
+
|
|
178
|
+
Represents a specific function invocation with captured inputs.
|
|
179
|
+
|
|
180
|
+
- `.fcn`: The parent `LineageFcn` (function wrapper)
|
|
181
|
+
- `.inputs`: Dict of captured input values
|
|
182
|
+
- `.outputs`: Tuple of `LineageFcnResult` results
|
|
183
|
+
- `.compute_lineage_hash()`: Generate lineage hash for cache key computation
|
|
184
|
+
|
|
185
|
+
### `LineageFcn`
|
|
186
|
+
|
|
187
|
+
The decorated function wrapper.
|
|
188
|
+
|
|
189
|
+
- `.fcn`: The original wrapped function
|
|
190
|
+
- `.hash`: SHA-256 hash of function bytecode
|
|
191
|
+
- `.invocations`: All `LineageFcnInvocation`s created from this
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# SciLineage
|
|
2
|
+
|
|
3
|
+
**Lineage tracking for Python data pipelines.**
|
|
4
|
+
|
|
5
|
+
SciLineage is a lightweight library for building data processing pipelines with automatic provenance tracking. It captures the full computational lineage of your results, enabling reproducibility and intelligent caching.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Automatic Lineage Tracking**: Every computation captures its inputs and function, building a complete provenance graph
|
|
10
|
+
- **Input Classification**: Automatically distinguishes variable inputs from constants for accurate lineage
|
|
11
|
+
- **Pluggable Caching**: Register a backend via `configure_backend()` to enable cache lookups via lineage hashes
|
|
12
|
+
- **Lightweight**: Core dependency is only `canonicalhash`
|
|
13
|
+
- **Type Safe**: Full type hints throughout
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install scilineage
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Basic Usage
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from scilineage import lineage_fcn
|
|
27
|
+
|
|
28
|
+
@lineage_fcn
|
|
29
|
+
def process(data, factor):
|
|
30
|
+
return data * factor
|
|
31
|
+
|
|
32
|
+
# Call returns a LineageFcnResult, not the raw result
|
|
33
|
+
result = process([1, 2, 3], 2)
|
|
34
|
+
|
|
35
|
+
# Access the computed value
|
|
36
|
+
print(result.data) # [2, 4, 6]
|
|
37
|
+
|
|
38
|
+
# Access lineage information
|
|
39
|
+
print(result.invoked.inputs) # {'arg_0': [1, 2, 3], 'arg_1': 2}
|
|
40
|
+
print(result.invoked.fcn.fcn.__name__) # 'process'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Multi-Output Functions
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
@lineage_fcn(unpack_output=True)
|
|
47
|
+
def split_data(data):
|
|
48
|
+
mid = len(data) // 2
|
|
49
|
+
return data[:mid], data[mid:]
|
|
50
|
+
|
|
51
|
+
first, second = split_data([1, 2, 3, 4])
|
|
52
|
+
print(first.data) # [1, 2]
|
|
53
|
+
print(second.data) # [3, 4]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Chaining Computations
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
@lineage_fcn
|
|
60
|
+
def normalize(data):
|
|
61
|
+
max_val = max(data)
|
|
62
|
+
return [x / max_val for x in data]
|
|
63
|
+
|
|
64
|
+
@lineage_fcn
|
|
65
|
+
def scale(data, factor):
|
|
66
|
+
return [x * factor for x in data]
|
|
67
|
+
|
|
68
|
+
raw = [10, 20, 30, 40]
|
|
69
|
+
normalized = normalize(raw)
|
|
70
|
+
scaled = scale(normalized, 100)
|
|
71
|
+
|
|
72
|
+
print(scaled.data) # [25.0, 50.0, 75.0, 100.0]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Extracting Lineage
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from scilineage import extract_lineage, get_upstream_lineage
|
|
79
|
+
|
|
80
|
+
@lineage_fcn
|
|
81
|
+
def step1(x):
|
|
82
|
+
return x + 1
|
|
83
|
+
|
|
84
|
+
@lineage_fcn
|
|
85
|
+
def step2(x):
|
|
86
|
+
return x * 2
|
|
87
|
+
|
|
88
|
+
result = step2(step1(5))
|
|
89
|
+
|
|
90
|
+
lineage = extract_lineage(result)
|
|
91
|
+
print(lineage.function_name) # 'step2'
|
|
92
|
+
print(lineage.function_hash) # SHA-256 of function bytecode
|
|
93
|
+
|
|
94
|
+
chain = get_upstream_lineage(result)
|
|
95
|
+
for record in chain:
|
|
96
|
+
print(f"{record['function_name']}: inputs={record['inputs']}")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Manual Interventions
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from scilineage import manual
|
|
103
|
+
|
|
104
|
+
# Step outside the pipeline for a manual correction
|
|
105
|
+
edited_data = [1, 2, 3]
|
|
106
|
+
|
|
107
|
+
# Re-enter the pipeline — the intervention is documented in lineage
|
|
108
|
+
corrected = manual(
|
|
109
|
+
edited_data,
|
|
110
|
+
label="outlier_removal",
|
|
111
|
+
reason="amplitude < 0.1 in trial 3 is sensor artifact",
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## API Reference
|
|
116
|
+
|
|
117
|
+
### `@lineage_fcn(unpack_output=False, unwrap=True, generates_file=False)`
|
|
118
|
+
|
|
119
|
+
Decorator to convert a function into a `LineageFcn`.
|
|
120
|
+
|
|
121
|
+
- `unpack_output`: Whether to unpack a tuple return into separate `LineageFcnResult`s
|
|
122
|
+
- `unwrap`: If True, automatically unwrap `LineageFcnResult` inputs to their raw data
|
|
123
|
+
- `generates_file`: If True, marks the function as producing files as side effects
|
|
124
|
+
|
|
125
|
+
### `LineageFcnResult`
|
|
126
|
+
|
|
127
|
+
Wrapper around computed values that carries lineage.
|
|
128
|
+
|
|
129
|
+
- `.data`: The actual computed value
|
|
130
|
+
- `.invoked`: The `LineageFcnInvocation` that produced this
|
|
131
|
+
- `.hash`: Unique hash based on computation lineage
|
|
132
|
+
- `.output_num`: Index for multi-output functions
|
|
133
|
+
|
|
134
|
+
### `LineageFcnInvocation`
|
|
135
|
+
|
|
136
|
+
Represents a specific function invocation with captured inputs.
|
|
137
|
+
|
|
138
|
+
- `.fcn`: The parent `LineageFcn` (function wrapper)
|
|
139
|
+
- `.inputs`: Dict of captured input values
|
|
140
|
+
- `.outputs`: Tuple of `LineageFcnResult` results
|
|
141
|
+
- `.compute_lineage_hash()`: Generate lineage hash for cache key computation
|
|
142
|
+
|
|
143
|
+
### `LineageFcn`
|
|
144
|
+
|
|
145
|
+
The decorated function wrapper.
|
|
146
|
+
|
|
147
|
+
- `.fcn`: The original wrapped function
|
|
148
|
+
- `.hash`: SHA-256 hash of function bytecode
|
|
149
|
+
- `.invocations`: All `LineageFcnInvocation`s created from this
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "scilineage"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Lineage tracking for Python data pipelines"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "SciStack Contributors" }
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"lineage",
|
|
17
|
+
"provenance",
|
|
18
|
+
"pipeline",
|
|
19
|
+
"data-science",
|
|
20
|
+
"reproducibility",
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Development Status :: 4 - Beta",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"Intended Audience :: Science/Research",
|
|
26
|
+
"License :: OSI Approved :: MIT License",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3.10",
|
|
30
|
+
"Programming Language :: Python :: 3.11",
|
|
31
|
+
"Programming Language :: Python :: 3.12",
|
|
32
|
+
"Topic :: Scientific/Engineering",
|
|
33
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
34
|
+
"Typing :: Typed",
|
|
35
|
+
]
|
|
36
|
+
dependencies = [
|
|
37
|
+
"canonicalhash>=0.1.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
numpy = ["numpy>=1.20"]
|
|
42
|
+
pandas = ["pandas>=1.3"]
|
|
43
|
+
all = ["numpy>=1.20", "pandas>=1.3"]
|
|
44
|
+
dev = [
|
|
45
|
+
"pytest>=7.0",
|
|
46
|
+
"pytest-cov>=4.0",
|
|
47
|
+
"mypy>=1.0",
|
|
48
|
+
"ruff>=0.1.0",
|
|
49
|
+
]
|
|
50
|
+
docs = [
|
|
51
|
+
"mkdocs>=1.5",
|
|
52
|
+
"mkdocs-material>=9.0",
|
|
53
|
+
"mkdocstrings[python]>=0.24",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[project.urls]
|
|
57
|
+
Documentation = "https://github.com/example/scilineage#readme"
|
|
58
|
+
Repository = "https://github.com/example/scilineage"
|
|
59
|
+
Issues = "https://github.com/example/scilineage/issues"
|
|
60
|
+
|
|
61
|
+
[tool.hatch.build.targets.sdist]
|
|
62
|
+
include = [
|
|
63
|
+
"/src",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[tool.hatch.build.targets.wheel]
|
|
67
|
+
packages = ["src/scilineage"]
|
|
68
|
+
|
|
69
|
+
[tool.pytest.ini_options]
|
|
70
|
+
testpaths = ["tests"]
|
|
71
|
+
pythonpath = ["src"]
|
|
72
|
+
|
|
73
|
+
[tool.mypy]
|
|
74
|
+
python_version = "3.10"
|
|
75
|
+
strict = true
|
|
76
|
+
warn_return_any = true
|
|
77
|
+
warn_unused_configs = true
|
|
78
|
+
|
|
79
|
+
[tool.ruff]
|
|
80
|
+
target-version = "py310"
|
|
81
|
+
line-length = 88
|
|
82
|
+
|
|
83
|
+
[tool.ruff.lint]
|
|
84
|
+
select = [
|
|
85
|
+
"E", # pycodestyle errors
|
|
86
|
+
"W", # pycodestyle warnings
|
|
87
|
+
"F", # Pyflakes
|
|
88
|
+
"I", # isort
|
|
89
|
+
"B", # flake8-bugbear
|
|
90
|
+
"C4", # flake8-comprehensions
|
|
91
|
+
"UP", # pyupgrade
|
|
92
|
+
]
|
|
93
|
+
ignore = [
|
|
94
|
+
"E501", # line too long (handled by formatter)
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
[tool.ruff.lint.isort]
|
|
98
|
+
known-first-party = ["scilineage"]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""SciLineage: Lineage Tracking for Python.
|
|
2
|
+
|
|
3
|
+
A lightweight library for building data processing pipelines with automatic
|
|
4
|
+
provenance tracking.
|
|
5
|
+
|
|
6
|
+
Features:
|
|
7
|
+
- Full lineage tracking for reproducibility
|
|
8
|
+
- Automatic input capture and output wrapping
|
|
9
|
+
- Lightweight (core dependency: canonicalhash)
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
from scilineage import lineage_fcn
|
|
13
|
+
|
|
14
|
+
@lineage_fcn
|
|
15
|
+
def process(data, factor):
|
|
16
|
+
return data * factor
|
|
17
|
+
|
|
18
|
+
result = process(input_data, 2.5) # Returns LineageFcnResult
|
|
19
|
+
print(result.data) # The computed value
|
|
20
|
+
print(result.invoked.inputs) # Captured inputs for provenance
|
|
21
|
+
|
|
22
|
+
For multi-output functions, use unpack_output=True:
|
|
23
|
+
|
|
24
|
+
@lineage_fcn(unpack_output=True)
|
|
25
|
+
def split(data):
|
|
26
|
+
return data[:len(data)//2], data[len(data)//2:]
|
|
27
|
+
|
|
28
|
+
first_half, second_half = split(my_data) # Each is a LineageFcnResult
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from .backend import configure_backend, _clear_backend
|
|
32
|
+
from .core import (
|
|
33
|
+
LineageFcnResult,
|
|
34
|
+
LineageFcnInvocation,
|
|
35
|
+
LineageFcn,
|
|
36
|
+
lineage_fcn,
|
|
37
|
+
manual,
|
|
38
|
+
make_tuple_unpacking_wrapper,
|
|
39
|
+
)
|
|
40
|
+
from .hashing import canonical_hash, compute_function_hash
|
|
41
|
+
from .inputs import InputKind, ClassifiedInput, classify_input, is_trackable_variable
|
|
42
|
+
from .lineage import (
|
|
43
|
+
LineageRecord,
|
|
44
|
+
extract_lineage,
|
|
45
|
+
get_raw_value,
|
|
46
|
+
get_upstream_lineage,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
__version__ = "0.1.0"
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
# Backend registry
|
|
53
|
+
"configure_backend",
|
|
54
|
+
# Core classes
|
|
55
|
+
"LineageFcn",
|
|
56
|
+
"LineageFcnInvocation",
|
|
57
|
+
"LineageFcnResult",
|
|
58
|
+
# Decorator
|
|
59
|
+
"lineage_fcn",
|
|
60
|
+
# Manual intervention
|
|
61
|
+
"manual",
|
|
62
|
+
# Tuple unpacking
|
|
63
|
+
"make_tuple_unpacking_wrapper",
|
|
64
|
+
# Input classification
|
|
65
|
+
"InputKind",
|
|
66
|
+
"ClassifiedInput",
|
|
67
|
+
"classify_input",
|
|
68
|
+
"is_trackable_variable",
|
|
69
|
+
# Lineage
|
|
70
|
+
"LineageRecord",
|
|
71
|
+
"extract_lineage",
|
|
72
|
+
"get_raw_value",
|
|
73
|
+
"get_upstream_lineage",
|
|
74
|
+
# Hashing
|
|
75
|
+
"canonical_hash",
|
|
76
|
+
"compute_function_hash",
|
|
77
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Backend registry for scilineage cache lookups.
|
|
2
|
+
|
|
3
|
+
Provides a module-level slot for a single cache backend. Higher-level packages
|
|
4
|
+
(scihist, scidb-net) register their database or network client here once at
|
|
5
|
+
startup. End users do not interact with this directly.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
_backend = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def configure_backend(backend) -> None:
|
|
12
|
+
"""Register a cache backend.
|
|
13
|
+
|
|
14
|
+
Called by scihist.configure_database() or scidb-net at startup.
|
|
15
|
+
Not intended to be called by end users directly.
|
|
16
|
+
"""
|
|
17
|
+
global _backend
|
|
18
|
+
_backend = backend
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _clear_backend() -> None:
|
|
22
|
+
"""Reset the backend to None. For use in tests."""
|
|
23
|
+
global _backend
|
|
24
|
+
_backend = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _get_backend():
|
|
28
|
+
"""Return the current backend, or None if not configured."""
|
|
29
|
+
return _backend
|