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.
@@ -0,0 +1,10 @@
1
+ .venv
2
+ .DS_Store
3
+ */*/__pycache__
4
+ others_projects/sciforge
5
+ scistack-gui/extension/node_modules/
6
+ scistack-gui/frontend/node_modules/__pycache__/
7
+ *.pyc
8
+ __pycache__/
9
+ *.pyc
10
+ *.pyo
@@ -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