expt-logger 0.1.0.dev0__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,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(uv run mypy:*)"
5
+ ]
6
+ }
7
+ }
@@ -0,0 +1,79 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ *.manifest
31
+ *.spec
32
+
33
+ # Unit test / coverage reports
34
+ htmlcov/
35
+ .tox/
36
+ .nox/
37
+ .coverage
38
+ .coverage.*
39
+ .cache
40
+ nosetests.xml
41
+ coverage.xml
42
+ *.cover
43
+ *.log
44
+ .pytest_cache/
45
+ .hypothesis/
46
+
47
+ # Virtual environments
48
+ .env
49
+ .venv
50
+ env/
51
+ venv/
52
+ ENV/
53
+ env.bak/
54
+ venv.bak/
55
+
56
+ # IDEs
57
+ .vscode/
58
+ .idea/
59
+ *.swp
60
+ *.swo
61
+ *~
62
+ .DS_Store
63
+
64
+ # Type checking
65
+ .mypy_cache/
66
+ .dmypy.json
67
+ dmypy.json
68
+ .pytype/
69
+
70
+ # Ruff
71
+ .ruff_cache/
72
+
73
+ # uv
74
+ uv.lock
75
+
76
+ # Project specific
77
+ *.db
78
+ *.sqlite
79
+ *.sqlite3
@@ -0,0 +1,69 @@
1
+ # Development
2
+
3
+ ## Setup
4
+
5
+ Install dependencies using uv:
6
+
7
+ ```bash
8
+ # Install the package with dev dependencies
9
+ uv sync --dev
10
+ ```
11
+
12
+ ## Running Tests
13
+
14
+ ```bash
15
+ uv run pytest
16
+ ```
17
+
18
+ With coverage:
19
+
20
+ ```bash
21
+ uv run pytest --cov=. --cov-report=html
22
+ ```
23
+
24
+ ## Linting
25
+
26
+ ```bash
27
+ # Check code
28
+ uv run ruff check .
29
+
30
+ # Format code
31
+ uv run ruff format .
32
+ ```
33
+
34
+ ## Type Checking
35
+
36
+ ```bash
37
+ uv run mypy .
38
+ ```
39
+
40
+ ## Making Changes
41
+
42
+ 1. Make your changes
43
+ 2. Run linting: `uv run ruff check . && uv run ruff format .`
44
+ 3. Run type checking: `uv run mypy .`
45
+ 4. Run tests: `uv run pytest`
46
+ 5. Test the demo: `uv run python demo.py`
47
+
48
+ ## Building
49
+
50
+ ```bash
51
+ uv build
52
+ ```
53
+
54
+ ## Versioning
55
+ To update to an exact version, provide it as a positional argument:
56
+ ```bash
57
+ uv version 1.0.0
58
+ ```
59
+
60
+ To increase the version of your package semantics, use the --bump option:
61
+ ```bash
62
+ uv version --bump dev
63
+ ```
64
+
65
+ ## Publishing
66
+
67
+ ```bash
68
+ uv publish
69
+ ```
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: expt-logger
3
+ Version: 0.1.0.dev0
4
+ Summary: Simple experiment logging library
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: httpx>=0.27.0
7
+ Description-Content-Type: text/markdown
8
+
9
+ # expt_logger
10
+
11
+ Simple experiment tracking for RL training with a W&B-style API.
12
+
13
+ ## Quick Start
14
+
15
+ **Install:**
16
+ ```bash
17
+ uv add expt-logger
18
+ # or
19
+ pip install expt-logger
20
+ ```
21
+
22
+ **Set your API key:**
23
+ ```bash
24
+ export EXPT_LOGGER_API_KEY=your_api_key
25
+ ```
26
+
27
+ **Start logging:**
28
+ ```python
29
+ import expt_logger
30
+
31
+ # Initialize run with config
32
+ run = expt_logger.init(
33
+ name="grpo-math",
34
+ config={"lr": 3e-6, "batch_size": 8}
35
+ )
36
+
37
+ # Get experiment URLs
38
+ print(f"View experiment: {run.experiment_url}")
39
+ print(f"Base URL: {run.base_url}")
40
+
41
+ # Log RL rollouts with rewards
42
+ expt_logger.log_rollout(
43
+ prompt="What is 2+2?",
44
+ messages=[{"role": "assistant", "content": "The answer is 4."}],
45
+ rewards={"correctness": 1.0, "format": 0.9},
46
+ mode="train"
47
+ )
48
+
49
+ # Log scalar metrics
50
+ expt_logger.log({
51
+ "train/loss": 0.45,
52
+ "train/kl": 0.02,
53
+ "train/reward": 0.85
54
+ })
55
+
56
+ expt_logger.end()
57
+ ```
58
+
59
+ ## Core Features
60
+
61
+ ### Scalar Metrics
62
+
63
+ Log training metrics with automatic step tracking:
64
+
65
+ ```python
66
+ # Auto-increment steps (defaults to "train" mode)
67
+ expt_logger.log({"loss": 0.5}) # step 0, train/loss
68
+ expt_logger.log({"loss": 0.4}) # step 1, train/loss
69
+
70
+ # Use slash prefixes for train/eval modes
71
+ expt_logger.log({
72
+ "train/loss": 0.5,
73
+ "eval/loss": 0.6
74
+ }, step=10)
75
+
76
+ # Or set mode explicitly
77
+ expt_logger.log({"loss": 0.5}, mode="eval")
78
+ ```
79
+
80
+ **Note:** Metrics default to `"train"` mode when no mode is specified and keys don't have slash prefixes.
81
+
82
+ **Batching metrics** at the same step:
83
+ ```python
84
+ expt_logger.log({"metric_a": 1.0}, commit=False)
85
+ expt_logger.log({"metric_b": 2.0}, commit=False)
86
+ expt_logger.log({"metric_c": 3.0}) # commits all three at step 0
87
+ ```
88
+
89
+ ### Rollouts (RL-specific)
90
+
91
+ Log conversation rollouts with multiple reward functions:
92
+
93
+ ```python
94
+ expt_logger.log_rollout(
95
+ prompt="Solve: x^2 - 5x + 6 = 0",
96
+ messages=[
97
+ {"role": "assistant", "content": "Let me factor this..."},
98
+ {"role": "user", "content": "Can you verify?"},
99
+ {"role": "assistant", "content": "Sure! (x-2)(x-3) = 0..."}
100
+ ],
101
+ rewards={
102
+ "correctness": 1.0,
103
+ "format": 0.9,
104
+ "helpfulness": 0.85
105
+ },
106
+ step=5,
107
+ mode="train"
108
+ )
109
+ ```
110
+
111
+ - **Messages format:** List of dicts with `"role"` and `"content"` keys
112
+ - **Rewards format:** Dict of reward names to float values
113
+ - **Mode:** `"train"` or `"eval"` (default: `"train"`)
114
+
115
+ ### Configuration
116
+
117
+ Track hyperparameters and update them dynamically:
118
+
119
+ ```python
120
+ run = expt_logger.init(config={"lr": 0.001, "batch_size": 32})
121
+
122
+ # Update config during training
123
+ run.config.lr = 0.0005 # attribute style
124
+ run.config["epochs"] = 100 # dict style
125
+ run.config.update({"model": "gpt2"}) # bulk update
126
+ ```
127
+
128
+ ### API Key & Server Configuration
129
+
130
+ **API Key** (required):
131
+ ```bash
132
+ export EXPT_LOGGER_API_KEY=your_api_key
133
+ ```
134
+ Or pass directly:
135
+ ```python
136
+ expt_logger.init(api_key="your_key")
137
+ ```
138
+
139
+ **Custom server URL** (optional, for self-hosting):
140
+ ```bash
141
+ export EXPT_LOGGER_BASE_URL=https://your-server.com
142
+ ```
143
+ Or:
144
+ ```python
145
+ expt_logger.init(base_url="https://your-server.com")
146
+ ```
147
+
148
+ ### Accessing Experiment URLs
149
+
150
+ Get the experiment URL and base URL from the run object:
151
+
152
+ ```python
153
+ run = expt_logger.init(name="my-experiment")
154
+
155
+ # Get the full experiment URL to view in browser
156
+ print(run.experiment_url)
157
+ # https://expt-platform.vercel.app/experiments/ccf1f879-50a6-492b-9072-fed6effac731
158
+
159
+ # Get the base URL of the tracking server
160
+ print(run.base_url)
161
+ # https://expt-platform.vercel.app
162
+ ```
163
+
164
+ ## API Reference
165
+
166
+ ### `expt_logger.init()`
167
+
168
+ ```python
169
+ init(
170
+ name: str | None = None,
171
+ config: dict[str, Any] | None = None,
172
+ api_key: str | None = None,
173
+ base_url: str | None = None
174
+ ) -> Run
175
+ ```
176
+
177
+ - `name`: Experiment name (auto-generated if not provided)
178
+ - `config`: Initial hyperparameters
179
+ - `api_key`: API key (or set `EXPT_LOGGER_API_KEY`)
180
+ - `base_url`: Custom server URL (or set `EXPT_LOGGER_BASE_URL`)
181
+
182
+ ### `expt_logger.log()`
183
+
184
+ ```python
185
+ log(
186
+ metrics: dict[str, float],
187
+ step: int | None = None,
188
+ mode: str | None = None,
189
+ commit: bool = True
190
+ )
191
+ ```
192
+
193
+ - `metrics`: Dict of metric names to values
194
+ - `step`: Step number (auto-increments if not provided)
195
+ - `mode`: Default mode for keys without slashes (default: `"train"`)
196
+ - `commit`: If `False`, buffer metrics until next `commit=True`
197
+
198
+ ### `expt_logger.log_rollout()`
199
+
200
+ ```python
201
+ log_rollout(
202
+ prompt: str,
203
+ messages: list[dict[str, str]],
204
+ rewards: dict[str, float],
205
+ step: int | None = None,
206
+ mode: str = "train"
207
+ )
208
+ ```
209
+
210
+ - `prompt`: The prompt text
211
+ - `messages`: List of `{"role": ..., "content": ...}` dicts
212
+ - `rewards`: Dict of reward names to values
213
+ - `step`: Step number (uses current step if not provided)
214
+ - `mode`: `"train"` or `"eval"`
215
+
216
+ ### `expt_logger.flush()` / `expt_logger.end()`
217
+
218
+ - `flush()`: Manually send buffered data to server
219
+ - `end()`: Finish the run (called automatically on exit)
220
+
221
+ ## Advanced
222
+
223
+ ### Context Manager
224
+
225
+ Ensures automatic cleanup:
226
+
227
+ ```python
228
+ with expt_logger.init(name="my-run") as run:
229
+ expt_logger.log({"loss": 0.5})
230
+ # end() called automatically
231
+ ```
232
+
233
+ ### Graceful Shutdown
234
+
235
+ The library handles cleanup on:
236
+ - Normal exit (`atexit`)
237
+ - Ctrl+C (`SIGINT`)
238
+ - `SIGTERM`
239
+
240
+ All buffered data is flushed before exit.
241
+
242
+ ## Development
243
+
244
+ For local development, see [DEVELOPMENT.md](DEVELOPMENT.md).
245
+
246
+ Run the demo:
247
+
248
+ ```bash
249
+ python demo.py # GRPO-style training simulation
250
+ python demo.py commit # Batching demo
251
+ python demo.py messages # Structured messages demo
252
+ ```
@@ -0,0 +1,244 @@
1
+ # expt_logger
2
+
3
+ Simple experiment tracking for RL training with a W&B-style API.
4
+
5
+ ## Quick Start
6
+
7
+ **Install:**
8
+ ```bash
9
+ uv add expt-logger
10
+ # or
11
+ pip install expt-logger
12
+ ```
13
+
14
+ **Set your API key:**
15
+ ```bash
16
+ export EXPT_LOGGER_API_KEY=your_api_key
17
+ ```
18
+
19
+ **Start logging:**
20
+ ```python
21
+ import expt_logger
22
+
23
+ # Initialize run with config
24
+ run = expt_logger.init(
25
+ name="grpo-math",
26
+ config={"lr": 3e-6, "batch_size": 8}
27
+ )
28
+
29
+ # Get experiment URLs
30
+ print(f"View experiment: {run.experiment_url}")
31
+ print(f"Base URL: {run.base_url}")
32
+
33
+ # Log RL rollouts with rewards
34
+ expt_logger.log_rollout(
35
+ prompt="What is 2+2?",
36
+ messages=[{"role": "assistant", "content": "The answer is 4."}],
37
+ rewards={"correctness": 1.0, "format": 0.9},
38
+ mode="train"
39
+ )
40
+
41
+ # Log scalar metrics
42
+ expt_logger.log({
43
+ "train/loss": 0.45,
44
+ "train/kl": 0.02,
45
+ "train/reward": 0.85
46
+ })
47
+
48
+ expt_logger.end()
49
+ ```
50
+
51
+ ## Core Features
52
+
53
+ ### Scalar Metrics
54
+
55
+ Log training metrics with automatic step tracking:
56
+
57
+ ```python
58
+ # Auto-increment steps (defaults to "train" mode)
59
+ expt_logger.log({"loss": 0.5}) # step 0, train/loss
60
+ expt_logger.log({"loss": 0.4}) # step 1, train/loss
61
+
62
+ # Use slash prefixes for train/eval modes
63
+ expt_logger.log({
64
+ "train/loss": 0.5,
65
+ "eval/loss": 0.6
66
+ }, step=10)
67
+
68
+ # Or set mode explicitly
69
+ expt_logger.log({"loss": 0.5}, mode="eval")
70
+ ```
71
+
72
+ **Note:** Metrics default to `"train"` mode when no mode is specified and keys don't have slash prefixes.
73
+
74
+ **Batching metrics** at the same step:
75
+ ```python
76
+ expt_logger.log({"metric_a": 1.0}, commit=False)
77
+ expt_logger.log({"metric_b": 2.0}, commit=False)
78
+ expt_logger.log({"metric_c": 3.0}) # commits all three at step 0
79
+ ```
80
+
81
+ ### Rollouts (RL-specific)
82
+
83
+ Log conversation rollouts with multiple reward functions:
84
+
85
+ ```python
86
+ expt_logger.log_rollout(
87
+ prompt="Solve: x^2 - 5x + 6 = 0",
88
+ messages=[
89
+ {"role": "assistant", "content": "Let me factor this..."},
90
+ {"role": "user", "content": "Can you verify?"},
91
+ {"role": "assistant", "content": "Sure! (x-2)(x-3) = 0..."}
92
+ ],
93
+ rewards={
94
+ "correctness": 1.0,
95
+ "format": 0.9,
96
+ "helpfulness": 0.85
97
+ },
98
+ step=5,
99
+ mode="train"
100
+ )
101
+ ```
102
+
103
+ - **Messages format:** List of dicts with `"role"` and `"content"` keys
104
+ - **Rewards format:** Dict of reward names to float values
105
+ - **Mode:** `"train"` or `"eval"` (default: `"train"`)
106
+
107
+ ### Configuration
108
+
109
+ Track hyperparameters and update them dynamically:
110
+
111
+ ```python
112
+ run = expt_logger.init(config={"lr": 0.001, "batch_size": 32})
113
+
114
+ # Update config during training
115
+ run.config.lr = 0.0005 # attribute style
116
+ run.config["epochs"] = 100 # dict style
117
+ run.config.update({"model": "gpt2"}) # bulk update
118
+ ```
119
+
120
+ ### API Key & Server Configuration
121
+
122
+ **API Key** (required):
123
+ ```bash
124
+ export EXPT_LOGGER_API_KEY=your_api_key
125
+ ```
126
+ Or pass directly:
127
+ ```python
128
+ expt_logger.init(api_key="your_key")
129
+ ```
130
+
131
+ **Custom server URL** (optional, for self-hosting):
132
+ ```bash
133
+ export EXPT_LOGGER_BASE_URL=https://your-server.com
134
+ ```
135
+ Or:
136
+ ```python
137
+ expt_logger.init(base_url="https://your-server.com")
138
+ ```
139
+
140
+ ### Accessing Experiment URLs
141
+
142
+ Get the experiment URL and base URL from the run object:
143
+
144
+ ```python
145
+ run = expt_logger.init(name="my-experiment")
146
+
147
+ # Get the full experiment URL to view in browser
148
+ print(run.experiment_url)
149
+ # https://expt-platform.vercel.app/experiments/ccf1f879-50a6-492b-9072-fed6effac731
150
+
151
+ # Get the base URL of the tracking server
152
+ print(run.base_url)
153
+ # https://expt-platform.vercel.app
154
+ ```
155
+
156
+ ## API Reference
157
+
158
+ ### `expt_logger.init()`
159
+
160
+ ```python
161
+ init(
162
+ name: str | None = None,
163
+ config: dict[str, Any] | None = None,
164
+ api_key: str | None = None,
165
+ base_url: str | None = None
166
+ ) -> Run
167
+ ```
168
+
169
+ - `name`: Experiment name (auto-generated if not provided)
170
+ - `config`: Initial hyperparameters
171
+ - `api_key`: API key (or set `EXPT_LOGGER_API_KEY`)
172
+ - `base_url`: Custom server URL (or set `EXPT_LOGGER_BASE_URL`)
173
+
174
+ ### `expt_logger.log()`
175
+
176
+ ```python
177
+ log(
178
+ metrics: dict[str, float],
179
+ step: int | None = None,
180
+ mode: str | None = None,
181
+ commit: bool = True
182
+ )
183
+ ```
184
+
185
+ - `metrics`: Dict of metric names to values
186
+ - `step`: Step number (auto-increments if not provided)
187
+ - `mode`: Default mode for keys without slashes (default: `"train"`)
188
+ - `commit`: If `False`, buffer metrics until next `commit=True`
189
+
190
+ ### `expt_logger.log_rollout()`
191
+
192
+ ```python
193
+ log_rollout(
194
+ prompt: str,
195
+ messages: list[dict[str, str]],
196
+ rewards: dict[str, float],
197
+ step: int | None = None,
198
+ mode: str = "train"
199
+ )
200
+ ```
201
+
202
+ - `prompt`: The prompt text
203
+ - `messages`: List of `{"role": ..., "content": ...}` dicts
204
+ - `rewards`: Dict of reward names to values
205
+ - `step`: Step number (uses current step if not provided)
206
+ - `mode`: `"train"` or `"eval"`
207
+
208
+ ### `expt_logger.flush()` / `expt_logger.end()`
209
+
210
+ - `flush()`: Manually send buffered data to server
211
+ - `end()`: Finish the run (called automatically on exit)
212
+
213
+ ## Advanced
214
+
215
+ ### Context Manager
216
+
217
+ Ensures automatic cleanup:
218
+
219
+ ```python
220
+ with expt_logger.init(name="my-run") as run:
221
+ expt_logger.log({"loss": 0.5})
222
+ # end() called automatically
223
+ ```
224
+
225
+ ### Graceful Shutdown
226
+
227
+ The library handles cleanup on:
228
+ - Normal exit (`atexit`)
229
+ - Ctrl+C (`SIGINT`)
230
+ - `SIGTERM`
231
+
232
+ All buffered data is flushed before exit.
233
+
234
+ ## Development
235
+
236
+ For local development, see [DEVELOPMENT.md](DEVELOPMENT.md).
237
+
238
+ Run the demo:
239
+
240
+ ```bash
241
+ python demo.py # GRPO-style training simulation
242
+ python demo.py commit # Batching demo
243
+ python demo.py messages # Structured messages demo
244
+ ```