flexlock 0.8.2__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.
@@ -0,0 +1,357 @@
1
+ Metadata-Version: 2.4
2
+ Name: flexlock
3
+ Version: 0.8.2
4
+ Summary: A lightweight and painless SciOps library
5
+ Author-email: Quentin Febvre <quentin.febvre@gmail.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: cloudpickle<4,>=3.0.0
9
+ Requires-Dist: gitpython<4,>=3.1.45
10
+ Requires-Dist: joblib<2,>=1.5.2
11
+ Requires-Dist: loguru<0.8,>=0.7.3
12
+ Requires-Dist: omegaconf<3,>=2.3.0
13
+ Requires-Dist: pandas<3,>=2.3.2
14
+ Requires-Dist: xxhash<4,>=3.5.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ # FlexLock
18
+
19
+ **Reproducible, Composable, and Scalable Computational Experiments**
20
+
21
+ [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://quentinf00.github.io/flexlock/)
22
+ [![PyPI version](https://badge.fury.io/py/flexlock.svg)](https://badge.fury.io/py/flexlock)
23
+ [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
24
+
25
+ FlexLock is a Python library that makes your computational experiments reproducible, composable, and efficient. It automatically tracks everything (code, config, data), detects when you're rerunning identical experiments (and skips them), and helps you build multi-stage pipelines that just work.
26
+
27
+ ## Why FlexLock?
28
+
29
+ ### The Problem
30
+
31
+ You're running ML experiments and:
32
+ - **Lost track**: "Which hyperparameters gave me that 95% accuracy?"
33
+ - **Can't reproduce**: "This worked last week, what changed?"
34
+ - **Wasting compute**: Running the same preprocessing 10 times
35
+ - **Pipeline chaos**: Multi-stage workflows that break constantly
36
+
37
+ ### The FlexLock Solution
38
+
39
+ ```python
40
+ from flexlock import flexcli
41
+
42
+ @flexcli
43
+ def train(lr=0.01, epochs=10):
44
+ # ... your training code ...
45
+ return {"accuracy": accuracy}
46
+ ```
47
+
48
+ That's it! You now have:
49
+ - ✅ **Automatic tracking**: Code, config, and data snapshots
50
+ - ✅ **Smart caching**: Never rerun identical experiments
51
+ - ✅ **CLI for free**: `python train.py -o lr=0.1`
52
+ - ✅ **Parameter sweeps**: `--sweep "0.001,0.01,0.1" --n_jobs 3`
53
+ - ✅ **Perfect reproducibility**: `flexlock diff` shows exactly what changed
54
+
55
+ ## Quick Start
56
+
57
+ ### Install
58
+
59
+ ```bash
60
+ pip install flexlock
61
+ ```
62
+
63
+ ### Example 1: Simple Script
64
+
65
+ ```python
66
+ # train.py
67
+ from flexlock import flexcli
68
+
69
+ @flexcli
70
+ def train(lr: float = 0.01, epochs: int = 10):
71
+ """Train a model."""
72
+ print(f"Training with lr={lr} for {epochs} epochs")
73
+ # ... training code ...
74
+ return {"accuracy": 0.95}
75
+
76
+ if __name__ == "__main__":
77
+ train()
78
+ ```
79
+
80
+ Run it:
81
+
82
+ ```bash
83
+ # Default run
84
+ $ python train.py
85
+ Training with lr=0.01 for 10 epochs
86
+ ✓ Results saved to: results/train/run_0001/
87
+
88
+ # Override parameters
89
+ $ python train.py -o lr=0.1 epochs=20
90
+
91
+ # Parameter sweep (runs 3 experiments in parallel)
92
+ $ python train.py --sweep "0.001,0.01,0.1" --sweep-target lr --n_jobs 3
93
+ ```
94
+
95
+ ### Example 2: Multi-Stage Pipeline
96
+
97
+ ```python
98
+ # pipeline.py
99
+ from flexlock.api import Project
100
+
101
+ # Load configurations
102
+ proj = Project(defaults='configs.defaults')
103
+
104
+ # Stage 1: Preprocess
105
+ preprocess_result = proj.submit(proj.get('preprocess'))
106
+
107
+ # Stage 2: Train (uses preprocess output)
108
+ train_cfg = proj.get('train')
109
+ train_cfg.data_dir = preprocess_result.output_dir
110
+ train_result = proj.submit(train_cfg)
111
+
112
+ # Stage 3: Evaluate
113
+ eval_cfg = proj.get('evaluate')
114
+ eval_cfg.model_dir = train_result.save_dir
115
+ eval_result = proj.submit(eval_cfg)
116
+
117
+ print(f"Final accuracy: {eval_result.accuracy}")
118
+ ```
119
+
120
+ Run it again? FlexLock automatically skips unchanged stages:
121
+
122
+ ```bash
123
+ $ python pipeline.py
124
+ ⚡ Cache Hit! Preprocess already done
125
+ ⚡ Cache Hit! Training already done
126
+ ⚡ Cache Hit! Evaluation already done
127
+ Final accuracy: 0.95
128
+ ```
129
+
130
+ ## Key Features
131
+
132
+ ### 🔒 Automatic Reproducibility
133
+
134
+ Every run creates a snapshot with:
135
+ - **Git tree hash**: Exact code state (not just commit)
136
+ - **Full configuration**: All parameters used
137
+ - **Data fingerprints**: Input data hashes
138
+ - **Environment**: System info
139
+
140
+ Compare any two runs:
141
+
142
+ ```bash
143
+ $ flexlock diff run_0001 run_0002
144
+ Differences found:
145
+ Config:
146
+ optimizer.lr: 0.001 → 0.01
147
+ Code:
148
+ Git tree: abc123 → def456 (model.py modified)
149
+ ```
150
+
151
+ ### ⚡ Smart Run Detection
152
+
153
+ FlexLock never wastes computation. It automatically detects when you're rerunning an experiment with identical inputs and reuses the cached result:
154
+
155
+ ```python
156
+ # First run: executes
157
+ result1 = proj.submit(config)
158
+
159
+ # Second run with same config: instant cache hit!
160
+ result2 = proj.submit(config) # ⚡ Skipped!
161
+ ```
162
+
163
+ This works even:
164
+ - Across different machines (with shared storage)
165
+ - Weeks later
166
+ - With different result directories (paths are normalized)
167
+
168
+ ### 🔄 Composable Pipelines
169
+
170
+ Build complex workflows from simple stages:
171
+
172
+ ```python
173
+ # Each stage is a function
174
+ def preprocess(input_data, output_dir): ...
175
+ def train(data_dir, model_type, lr): ...
176
+ def evaluate(model_dir, test_data): ...
177
+
178
+ # Compose them into a pipeline
179
+ proj = Project(defaults='configs.defaults')
180
+
181
+ prep = proj.submit(proj.get('preprocess'))
182
+ train_cfg = proj.get('train')
183
+ train_cfg.data_dir = prep.output_dir
184
+ model = proj.submit(train_cfg)
185
+
186
+ eval_cfg = proj.get('evaluate')
187
+ eval_cfg.model_dir = model.save_dir
188
+ results = proj.submit(eval_cfg)
189
+ ```
190
+
191
+ Failed at train? Fix it and rerun - FlexLock skips the successful preprocess stage.
192
+
193
+ ### 🚀 Parallel Execution
194
+
195
+ Run sweeps in parallel automatically:
196
+
197
+ ```python
198
+ # Define sweep
199
+ sweep = [
200
+ {"lr": 0.001, "batch_size": 32},
201
+ {"lr": 0.01, "batch_size": 32},
202
+ {"lr": 0.1, "batch_size": 64}
203
+ ]
204
+
205
+ # Run in parallel (local multiprocessing)
206
+ results = proj.submit(config, sweep=sweep, n_jobs=4)
207
+
208
+ # Or on a cluster (Slurm, PBS)
209
+ results = proj.submit(config, sweep=sweep, slurm_config="slurm.yaml")
210
+ ```
211
+
212
+ ### 📊 Configuration Management
213
+
214
+ Three ways to configure, all type-safe:
215
+
216
+ ```python
217
+ # Method 1: @flexcli (simplest)
218
+ @flexcli
219
+ def train(lr=0.01, epochs=10): ...
220
+
221
+ # Method 2: Python configs (most powerful)
222
+ from flexlock import py2cfg
223
+ config = py2cfg(
224
+ train,
225
+ model=py2cfg(Transformer, layers=12, hidden_size=768),
226
+ optimizer=py2cfg(Adam, lr=0.001),
227
+ epochs=100
228
+ )
229
+
230
+ # Method 3: YAML (declarative)
231
+ # config.yaml
232
+ train:
233
+ model:
234
+ layers: 12
235
+ hidden_size: 768
236
+ optimizer:
237
+ type: adam
238
+ lr: 0.001
239
+ epochs: 100
240
+ ```
241
+
242
+ ## Philosophy
243
+
244
+ FlexLock is built on three principles:
245
+
246
+ 1. **Configuration is Code**: Use Python's full expressiveness or YAML's simplicity
247
+ 2. **Automatic Reproducibility**: Every run is tracked, no manual logging needed
248
+ 3. **Smart Execution**: Never rerun identical experiments
249
+
250
+ Read more in the [Philosophy & Design](https://quentinf00.github.io/flexlock/philosophy.html) docs.
251
+
252
+ ## Documentation
253
+
254
+ - **[Quickstart Guide](https://quentinf00.github.io/flexlock/quickstart.html)**: Get started in 5 minutes
255
+ - **[Tutorials](https://quentinf00.github.io/flexlock/tutorials/)**: Learn by example
256
+ - [01. Basics](https://quentinf00.github.io/flexlock/tutorials/01_basics.html): `@flexcli`, CLI args, sweeps
257
+ - [02. Reproducibility](https://quentinf00.github.io/flexlock/tutorials/02_reproducibility.html): Snapshots, diffs
258
+ - [03. YAML Configs](https://quentinf00.github.io/flexlock/tutorials/03_yaml_config.html): Multi-stage YAML
259
+ - [04. Python Configs](https://quentinf00.github.io/flexlock/tutorials/04_python_config.html): `py2cfg`, nested objects
260
+ - [05. Pipelines](https://quentinf00.github.io/flexlock/tutorials/05_pipeline.html): Multi-stage workflows
261
+ - **[User Guide](https://quentinf00.github.io/flexlock/getting_started.html)**: In-depth feature docs
262
+ - **[API Reference](https://quentinf00.github.io/flexlock/api.html)**: Complete API documentation
263
+
264
+ ## Installation
265
+
266
+ ### From PyPI
267
+
268
+ ```bash
269
+ pip install flexlock
270
+ ```
271
+
272
+ ### From Conda
273
+
274
+ ```bash
275
+ conda install -c quentinf00 flexlock
276
+ ```
277
+
278
+ ### From Source
279
+
280
+ ```bash
281
+ git clone https://github.com/quentinf00/flexlock.git
282
+ cd flexlock
283
+ pip install -e .
284
+ ```
285
+
286
+ ## Requirements
287
+
288
+ - Python 3.8+
289
+ - OmegaConf
290
+ - Loguru
291
+ - PyYAML
292
+
293
+ ## Use Cases
294
+
295
+ ### ✅ Perfect For:
296
+
297
+ - **ML Research**: Hyperparameter tuning, ablation studies, architecture search
298
+ - **Data Science**: Exploratory analysis with automatic tracking
299
+ - **Scientific Computing**: Parameter sweeps, reproducible experiments
300
+ - **Data Pipelines**: Multi-stage ETL with dependency tracking
301
+ - **AutoML**: Large-scale hyperparameter optimization
302
+
303
+ ### ⚠️ Less Suitable For:
304
+
305
+ - **Production APIs**: Use Flask/FastAPI for serving models
306
+ - **Real-time Systems**: FlexLock is for offline experiments
307
+ - **Simple One-Off Scripts**: Adds overhead for single-run scripts
308
+
309
+ ## Comparison with Other Tools
310
+
311
+ | Feature | FlexLock | Hydra | MLflow | DVC |
312
+ |---------|----------|-------|--------|-----|
313
+ | **Configuration** | Python + YAML | YAML | Code | YAML |
314
+ | **Reproducibility** | Automatic | Manual | Partial | Partial |
315
+ | **Smart Caching** | ✅ | ❌ | ❌ | ✅ |
316
+ | **Multi-stage Pipelines** | ✅ | ❌ | ❌ | ✅ |
317
+ | **Parallel Sweeps** | ✅ | ✅ | ❌ | ❌ |
318
+ | **Learning Curve** | Low | Medium | Low | High |
319
+
320
+ ## Contributing
321
+
322
+ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
323
+
324
+ ## License
325
+
326
+ MIT License. See [LICENSE](LICENSE) for details.
327
+
328
+ ## Citation
329
+
330
+ If you use FlexLock in your research, please cite:
331
+
332
+ ```bibtex
333
+ @software{flexlock2024,
334
+ title = {FlexLock: Reproducible, Composable, and Scalable Computational Experiments},
335
+ author = {FlexLock Team},
336
+ year = {2024},
337
+ url = {https://github.com/quentinf00/flexlock}
338
+ }
339
+ ```
340
+
341
+ ## Acknowledgments
342
+
343
+ FlexLock builds on ideas from:
344
+ - **Hydra**: Configuration composition patterns
345
+ - **MLflow**: Experiment tracking concepts
346
+ - **DVC**: Pipeline dependency tracking
347
+ - **Sacred**: Experiment observation patterns
348
+
349
+ ## Support
350
+
351
+ - **Documentation**: [https://quentinf00.github.io/flexlock/](https://quentinf00.github.io/flexlock/)
352
+ - **GitHub Issues**: [Report bugs](https://github.com/quentinf00/flexlock/issues)
353
+ - **Discussions**: [Ask questions](https://github.com/quentinf00/flexlock/discussions)
354
+
355
+ ---
356
+
357
+ Made with ❤️ by the FlexLock team
@@ -0,0 +1,45 @@
1
+ flexlock/__init__.py,sha256=9c_D3abgUdb7xrXsreDfh9NJ00UHOf7qjszSdp3AwoQ,2226
2
+ flexlock/api.py,sha256=b-utO_O6Vwd4EzeVFtn9d_JVYl7WjluCWlgbyD4JIME,59957
3
+ flexlock/cli.py,sha256=Qrq2o6AipAnGd5W8weq0o8h3IgY2kPmXYkJiV7wqPb4,32403
4
+ flexlock/config.py,sha256=1hJCLJZHdNC6RrJKqhdb320yOMEFdUiXkvLMlwLolz0,4006
5
+ flexlock/context.py,sha256=WzFhGFI-zMUMTdGWfi3i3yAN_iyA2SbxuYZfZ_VCwbw,280
6
+ flexlock/data_hash.py,sha256=MOkt2KUgCzGTihZVZYOKuCNMmK9qiHOPPtzHLfyERKk,10433
7
+ flexlock/debug.py,sha256=y4zxz75_ntfhvT0F7vEoH7NhnEaymu9Fm9Ie5Ccs1CI,14858
8
+ flexlock/diff.py,sha256=CXK7zNPHSu6uoPQ5jlKYpxsCzWe537XSTxaor7kBt6k,9554
9
+ flexlock/diff_cli.py,sha256=LxSR7Y6nO816TYlZ1GU52BU5WXJ70WFgjLvd73snucE,5750
10
+ flexlock/exceptions.py,sha256=9ADrXSGPqyMkDdDfEt-L5fTTCNZePDn3FbUM8xxiQc4,1065
11
+ flexlock/export.py,sha256=hEcxgCTySnfQHSysiWHusDFvTz3ondUJQRN6jK2mRcY,3956
12
+ flexlock/fingerprint.py,sha256=PUsP1aN-ZHVD5wJl7yDbXWABDS0gNTLLa03t7a0PzAg,4538
13
+ flexlock/flexcli.py,sha256=FggMh-yiD8s3sxdG4po5yhxtDxLzhSI0Tm6v8m9P618,5204
14
+ flexlock/freeze.py,sha256=QdE3XlIbNV0tN8mnvyfSwz8iW1Pt7BixemM6ijWGxhU,11241
15
+ flexlock/git_utils.py,sha256=N71kQjVCloSGGVhwpGHpCCj36DnQSzVi1k1hs3VJEtI,6045
16
+ flexlock/index.py,sha256=XqLQoDHbkp1RvyLesuaH8OraQl5YHlrW_RzpcSfxfVQ,9651
17
+ flexlock/load_stage.py,sha256=GrHGzPAFen13zTdmYdjI2ggrXFH0tvsVdR24ifoA8_E,2017
18
+ flexlock/mlflow.py,sha256=RwRIw9KYMOkH7sO42CMIkfrTgELp2IvdzSuGuguhAAI,7680
19
+ flexlock/parallel.py,sha256=NQrfHf3pNY-62cyfRjjYYAKYvU_zPS630kq3GzHI29A,16662
20
+ flexlock/query.py,sha256=j-Q89CyQz0HYua_QzRFb-5rA85Y1hb6o7Sq_A_aVDB4,26683
21
+ flexlock/report.py,sha256=bLcy2h9HhYo0lX6PFG-Yb2cILbv4gPD6dKwUYYGgl-E,2564
22
+ flexlock/report_template.html,sha256=6fz7DAs6cGl1PF3P0s3WpVYj-t330L2Q-68s1Ymhaz4,10375
23
+ flexlock/resolvers.py,sha256=bzaVIlaht0BzBnBchbitsYLTw-F_8d46QXbY-06SVCE,9100
24
+ flexlock/run_cli.py,sha256=Z2sdNUsVQDzK3-v1cyWGCtg16HebFE50kkPZ_3q11iw,1285
25
+ flexlock/run_record.py,sha256=cqEL7LyighrzwuZqJ8NOiJdFmqDxKzuEnHNSqMtQ3II,6710
26
+ flexlock/runner.py,sha256=NM3PmONey6i40jKPhWyF6qOaC-h4HBFVvbiyiJQYG80,23401
27
+ flexlock/save_dir.py,sha256=LUc204z4RsIqvYZoXsdSl4Va7gF0lUoSmBgATl5DUs8,8567
28
+ flexlock/snapshot.py,sha256=9mPsQNc70404jx-nIUpR8rDiFjTJ7JjIV21K_i9oDIc,8887
29
+ flexlock/status_cli.py,sha256=cFYIl1Z_8SoMQJ0fuf3ntZJh5Y_AzK-31_09qYIcGaU,10217
30
+ flexlock/taskdb.py,sha256=BJ_OiryyumNskljDm-NQpZPMun7b66yi1FeYqYv1w_g,23276
31
+ flexlock/utils.py,sha256=4A4MdM7CNKWWpz_nse0F7KIOHnA54L9a2sSMayooPtQ,26250
32
+ flexlock/worker.py,sha256=phQrOpQUBHkFpsFh7tr2VdZfkytEfLQhLs7xJN5f0fM,9024
33
+ flexlock/worker_cli.py,sha256=qEB27EqP3W1YoQASlIbqbHx4Njq_xGOVcxnZqK3IIXY,4973
34
+ flexlock/backends/__init__.py,sha256=tHK-B_om2eRHl94H_arZqM8WFgLVmJoEIWIeXxJcrOs,205
35
+ flexlock/backends/base.py,sha256=hJaQW9Fgpym_2rZs31nOtbCjloGO4V8hoB5vVSp9fxk,1057
36
+ flexlock/backends/pbs.py,sha256=X-1LRFNJPKJkumJpF4lIJdxICbop0P3hKa_PqDRsRsg,7382
37
+ flexlock/backends/slurm.py,sha256=qmG5twnGC7CQPoOBpLoRmZ9QRifWkStfXiSTn7JJLI0,12230
38
+ flexlock/skills/flexlock-new-stage/SKILL.md,sha256=KCuurVRsGP3Tf_DF2bMlY7MEhcgDxn0LW10j-nzMmxc,2502
39
+ flexlock/skills/flexlock-report/SKILL.md,sha256=O-m8Rglhttw3IB-s9M3K2rpq-oiOuYr8jZ4cUlv7MHI,1671
40
+ flexlock/skills/flexlock-run-and-watch/SKILL.md,sha256=SycdkUekgHl9EFpCmtpEHgLNk0_CxU5NujjmE_m71IQ,2332
41
+ flexlock/skills/flexlock-survey/SKILL.md,sha256=I4imIn2yomW1cOinbZn8pCaxxXFIJXxFi-g5tSP8VXM,2315
42
+ flexlock-0.8.2.dist-info/METADATA,sha256=zGtEJoEHfY1dpopLY71_orYtVH6mcuuZQRsJQw9o5B4,9797
43
+ flexlock-0.8.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
44
+ flexlock-0.8.2.dist-info/entry_points.txt,sha256=JRQDXmol961tfxHc_VDFvJqpsFC-GjSI5XZ1ayGGBwc,248
45
+ flexlock-0.8.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,7 @@
1
+ [console_scripts]
2
+ flexlock = flexlock.cli:main
3
+ flexlock-diff = flexlock.diff_cli:main
4
+ flexlock-export = flexlock.export:main
5
+ flexlock-run = flexlock.run_cli:main
6
+ flexlock-status = flexlock.status_cli:main
7
+ flexlock-worker = flexlock.worker_cli:main