pam-python 0.2.0__tar.gz → 0.2.1__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.
- {pam_python-0.2.0 → pam_python-0.2.1}/PKG-INFO +49 -49
- {pam_python-0.2.0 → pam_python-0.2.1}/README.md +43 -26
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/__init__.py +1 -1
- pam_python-0.2.1/pam/cli.py +354 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/models/request_command.py +4 -0
- pam_python-0.2.1/pam/request_file_format.py +14 -0
- pam_python-0.2.1/pam/result_batch_uploader.py +227 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/server.py +22 -2
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/service.py +38 -25
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/AGENT.md +48 -68
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/REPORTS.md +2 -2
- pam_python-0.2.1/pam/templates/init/dockerignore.tmpl +6 -0
- pam_python-0.2.1/pam/templates/project/pip/Dockerfile +16 -0
- {pam_python-0.2.0/pam/templates/init → pam_python-0.2.1/pam/templates/project/pip}/requirements.txt +0 -2
- pam_python-0.2.1/pam/templates/project/uv/Dockerfile +20 -0
- pam_python-0.2.1/pam/templates/project/uv/pyproject.toml +12 -0
- pam_python-0.2.1/pam/templates/project/uv/python-version +1 -0
- pam_python-0.2.1/pam/templates/service/pandas/functions.tmpl +13 -0
- {pam_python-0.2.0/pam/templates/service → pam_python-0.2.1/pam/templates/service/pandas}/service.test.tmpl +31 -46
- pam_python-0.2.1/pam/templates/service/pandas/service_class.tmpl +65 -0
- pam_python-0.2.1/pam/templates/service/polars/functions.tmpl +11 -0
- pam_python-0.2.1/pam/templates/service/polars/service.test.tmpl +122 -0
- pam_python-0.2.1/pam/templates/service/polars/service_class.tmpl +59 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/tester_task.py +22 -7
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/utils.py +2 -4
- {pam_python-0.2.0 → pam_python-0.2.1}/pam_python.egg-info/PKG-INFO +49 -49
- {pam_python-0.2.0 → pam_python-0.2.1}/pam_python.egg-info/SOURCES.txt +14 -7
- pam_python-0.2.1/pam_python.egg-info/requires.txt +3 -0
- pam_python-0.2.1/pyproject.toml +54 -0
- pam_python-0.2.1/tests/test_cli_templates.py +133 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_result_batch_uploader.py +28 -2
- pam_python-0.2.1/tests/test_service_dataframe_output.py +41 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_sqlite_download_v2.py +21 -0
- pam_python-0.2.0/pam/cli.py +0 -226
- pam_python-0.2.0/pam/request_file_format.py +0 -5
- pam_python-0.2.0/pam/result_batch_uploader.py +0 -179
- pam_python-0.2.0/pam/templates/docker/Dockerfile +0 -21
- pam_python-0.2.0/pam/templates/init/dockerignore.tmpl +0 -4
- pam_python-0.2.0/pam/templates/service/functions.tmpl +0 -22
- pam_python-0.2.0/pam/templates/service/service_class.tmpl +0 -81
- pam_python-0.2.0/pam_python.egg-info/requires.txt +0 -9
- pam_python-0.2.0/setup.py +0 -43
- pam_python-0.2.0/tests/test_cli_templates.py +0 -78
- {pam_python-0.2.0 → pam_python-0.2.1}/LICENSE.txt +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/api.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/interface_task_manager.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/logger.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/models/__init__.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/models/sqlite_download.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/__init__.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/area.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/axis.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/bar.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/box_plot.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/bubble.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/candlestick.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/collection.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/definition.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/donut.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/errors.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/fields.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/heatmap.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/line.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/manager.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/metric.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/pie.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/polar_area.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/radar.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/radial_bar.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/range_area.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/range_bar.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/range_transform.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/record.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/scatter.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/schema.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/store.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/table.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/transport.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/reports/treemap.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/sqlite.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/task_manager.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/temp_file_utils.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/buildcmd/pamb +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/buildcmd/pamb-base.sh +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/gitignore.tmpl +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/main.tmpl +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/pylintrc.tmpl +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/run_unit_test.bat +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/run_unit_test.ps1 +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam/templates/init/run_unit_test.sh +0 -0
- {pam_python-0.2.0/pam/templates/service → pam_python-0.2.1/pam/templates/service/common}/service.yaml +1 -1
- {pam_python-0.2.0 → pam_python-0.2.1}/pam_python.egg-info/dependency_links.txt +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam_python.egg-info/entry_points.txt +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/pam_python.egg-info/top_level.txt +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/setup.cfg +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_range_transform.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_report_store.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_area_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_bar_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_box_plot_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_bubble_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_candlestick_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_donut_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_heatmap_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_line_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_metric_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_pie_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_polar_area_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_radar_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_radial_bar_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_range_area_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_range_bar_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_scatter_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_table_report.py +0 -0
- {pam_python-0.2.0 → pam_python-0.2.1}/tests/test_typed_treemap_report.py +0 -0
|
@@ -1,39 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pam-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Pam Python Library
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Author-email: narongrit@pams.ai
|
|
5
|
+
Author-email: Narongrit Kanhanoi <narongrit@pams.ai>
|
|
6
|
+
Project-URL: Homepage, https://github.com/heart/pam-python
|
|
8
7
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.
|
|
10
|
-
Classifier: License :: Other/Proprietary License
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
9
|
Classifier: Operating System :: OS Independent
|
|
12
10
|
Classifier: Intended Audience :: Developers
|
|
13
11
|
Classifier: Intended Audience :: Customer Service
|
|
14
12
|
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
-
Requires-Python:
|
|
13
|
+
Requires-Python: <3.13,>=3.12
|
|
16
14
|
Description-Content-Type: text/markdown
|
|
17
15
|
License-File: LICENSE.txt
|
|
18
|
-
Requires-Dist: setuptools>=70.0.0
|
|
19
16
|
Requires-Dist: Flask>=3.0.2
|
|
20
|
-
Requires-Dist: aiohttp>=3.11.11
|
|
21
|
-
Requires-Dist: pandas>=2.2.3
|
|
22
|
-
Requires-Dist: dask>=2024.12.1
|
|
23
|
-
Requires-Dist: dask-expr>=1.1.21
|
|
24
17
|
Requires-Dist: requests>=2.32.3
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist: pyarrow>=19.0.1
|
|
27
|
-
Dynamic: author
|
|
28
|
-
Dynamic: author-email
|
|
29
|
-
Dynamic: classifier
|
|
30
|
-
Dynamic: description
|
|
31
|
-
Dynamic: description-content-type
|
|
32
|
-
Dynamic: home-page
|
|
18
|
+
Requires-Dist: PyYAML>=6.0.2
|
|
33
19
|
Dynamic: license-file
|
|
34
|
-
Dynamic: requires-dist
|
|
35
|
-
Dynamic: requires-python
|
|
36
|
-
Dynamic: summary
|
|
37
20
|
|
|
38
21
|
# pam-python-data-plugin-framework
|
|
39
22
|
|
|
@@ -41,8 +24,6 @@ This repository provides the `pam` CLI and runtime framework to build Data Plugi
|
|
|
41
24
|
|
|
42
25
|
This README is a practical, step-by-step guide you can follow to create and run a real service.
|
|
43
26
|
|
|
44
|
-
Current release target: **0.2.0**
|
|
45
|
-
|
|
46
27
|
**What you get**
|
|
47
28
|
|
|
48
29
|
- CLI to initialize a project and scaffold services
|
|
@@ -72,25 +53,26 @@ Current release target: **0.2.0**
|
|
|
72
53
|
|
|
73
54
|
**Prerequisites**
|
|
74
55
|
|
|
75
|
-
- Python 3.
|
|
76
|
-
- `
|
|
56
|
+
- Python 3.12
|
|
57
|
+
- `uv` (recommended) or `pip`
|
|
77
58
|
|
|
78
59
|
---
|
|
79
60
|
|
|
80
61
|
**Install**
|
|
81
|
-
|
|
62
|
+
Recommended installation:
|
|
82
63
|
|
|
83
64
|
```bash
|
|
84
65
|
mkdir my_data_plugin
|
|
85
66
|
cd my_data_plugin
|
|
86
|
-
|
|
87
|
-
source venv/bin/activate
|
|
67
|
+
uv tool install pam-python
|
|
88
68
|
```
|
|
89
69
|
|
|
90
|
-
|
|
70
|
+
Pip remains supported:
|
|
91
71
|
|
|
92
72
|
```bash
|
|
93
|
-
|
|
73
|
+
python3 -m venv venv
|
|
74
|
+
source venv/bin/activate
|
|
75
|
+
python -m pip install pam-python
|
|
94
76
|
```
|
|
95
77
|
|
|
96
78
|
---
|
|
@@ -103,23 +85,26 @@ rules and `REPORTS.md` for the managed-report public API and copyable examples.
|
|
|
103
85
|
pam init
|
|
104
86
|
```
|
|
105
87
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- keep
|
|
110
|
-
- merge
|
|
88
|
+
`pam init` asks you to select `uv` (default) or `pip`. A uv project contains
|
|
89
|
+
`pyproject.toml`, `.python-version`, and `uv.lock`; a pip project contains
|
|
90
|
+
`requirements.txt`. The two templates are independent and are never mixed.
|
|
111
91
|
|
|
112
|
-
|
|
92
|
+
Initialization only supports a new project directory and will not migrate or
|
|
93
|
+
overwrite an existing project.
|
|
113
94
|
|
|
114
95
|
---
|
|
115
96
|
|
|
116
97
|
**Create a Service**
|
|
117
|
-
Generate a service scaffold. Do not hand-create service templates.
|
|
118
98
|
|
|
119
99
|
```bash
|
|
120
100
|
pam new service rfm_segment
|
|
121
101
|
```
|
|
122
102
|
|
|
103
|
+
The generator asks you to select Polars (default) or Pandas. Polars services use
|
|
104
|
+
lazy Parquet processing. Pandas services also receive Parquet and install
|
|
105
|
+
`pandas` plus `pyarrow`. The selected direct dependencies are added to the
|
|
106
|
+
project automatically.
|
|
107
|
+
|
|
123
108
|
This creates a new folder (e.g. `rfm_segment/`) with:
|
|
124
109
|
|
|
125
110
|
- a service class (`RfmSegmentSvc.py`)
|
|
@@ -141,7 +126,8 @@ The runtime calls your service in two main phases.
|
|
|
141
126
|
2. `on_data_input`
|
|
142
127
|
|
|
143
128
|
- Called when CDP sends input files
|
|
144
|
-
- `req.input_files` contains ordered
|
|
129
|
+
- `req.input_files` contains ordered Parquet files
|
|
130
|
+
- `req.file_format` is the typed format sent by PAM
|
|
145
131
|
- Should also return quickly (use a thread if needed)
|
|
146
132
|
|
|
147
133
|
When your service is done:
|
|
@@ -169,7 +155,11 @@ Notes:
|
|
|
169
155
|
---
|
|
170
156
|
|
|
171
157
|
**Uploading Results in Batches**
|
|
172
|
-
|
|
158
|
+
Polars templates pass `LazyFrame` results directly to `_upload_result(...)`, which
|
|
159
|
+
streams them to the CSV upload boundary. Do not collect or convert to Pandas first.
|
|
160
|
+
|
|
161
|
+
For eager Polars or Pandas DataFrames, use the batch uploader to handle chunking
|
|
162
|
+
and flushing automatically.
|
|
173
163
|
|
|
174
164
|
Recommended usage:
|
|
175
165
|
|
|
@@ -189,6 +179,7 @@ Notes:
|
|
|
189
179
|
- `options` may be passed to `upload(...)` and are forwarded to `_upload_result`.
|
|
190
180
|
- Complete batches upload immediately; `flush()` sends the remaining rows.
|
|
191
181
|
- `get_status()` returns buffered rows, uploaded rows, and uploaded batch counts per stream.
|
|
182
|
+
- `ResultBatchUploader` intentionally rejects Polars `LazyFrame`; upload it directly.
|
|
192
183
|
|
|
193
184
|
---
|
|
194
185
|
|
|
@@ -225,7 +216,8 @@ Important rules:
|
|
|
225
216
|
The generated `main.py` runs the Flask server.
|
|
226
217
|
|
|
227
218
|
```bash
|
|
228
|
-
python main.py
|
|
219
|
+
uv run python main.py # uv project
|
|
220
|
+
python main.py # pip project
|
|
229
221
|
```
|
|
230
222
|
|
|
231
223
|
By default it binds to `0.0.0.0:8000`. You can override with:
|
|
@@ -238,9 +230,13 @@ export SERVER_PORT=8000
|
|
|
238
230
|
---
|
|
239
231
|
|
|
240
232
|
**Testing a Service**
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
233
|
+
For uv projects, use one cross-platform command:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
uv run python -m unittest discover -s rfm_segment -p "test_*.py"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Pip projects include shell-specific scripts:
|
|
244
240
|
|
|
245
241
|
macOS/Linux:
|
|
246
242
|
|
|
@@ -285,20 +281,23 @@ After `pam init` and one service:
|
|
|
285
281
|
├── AGENT.md
|
|
286
282
|
├── REPORTS.md
|
|
287
283
|
├── Dockerfile
|
|
284
|
+
├── pyproject.toml
|
|
285
|
+
├── uv.lock
|
|
286
|
+
├── .python-version
|
|
288
287
|
├── rfm_segment/
|
|
289
288
|
│ ├── RfmSegmentSvc.py
|
|
290
289
|
│ ├── functions.py
|
|
291
290
|
│ ├── service.yaml
|
|
292
291
|
│ └── test_rfm_segment.py
|
|
293
|
-
|
|
294
|
-
└── run_unit_test.sh
|
|
292
|
+
└── .pam-project
|
|
295
293
|
```
|
|
296
294
|
|
|
297
295
|
---
|
|
298
296
|
|
|
299
297
|
**Troubleshooting**
|
|
300
298
|
|
|
301
|
-
- If `pam`
|
|
299
|
+
- If `pam` is missing, verify the uv tool installation or activate the pip virtualenv.
|
|
300
|
+
- If uv initialization fails, verify `uv` is on `PATH` and package indexes are reachable.
|
|
302
301
|
- If `pam new service` fails, confirm the service name is provided.
|
|
303
302
|
- If temp cleanup is too frequent or too slow, adjust `TEMP_CLEAN_INTERVAL_HOURS` and `TEMP_CLEAN_DAYS`.
|
|
304
303
|
|
|
@@ -309,5 +308,6 @@ After `pam init` and one service:
|
|
|
309
308
|
- Implement your logic in `functions.py`.
|
|
310
309
|
- Wire it into `on_start` and `on_data_input` in your service class.
|
|
311
310
|
- Use the temp utilities to write intermediate files.
|
|
312
|
-
-
|
|
311
|
+
- Keep Polars transformations lazy and upload the resulting `LazyFrame` directly.
|
|
312
|
+
- Use `ResultBatchUploader` only for eager Polars/Pandas frames that need row batching.
|
|
313
313
|
- Read `REPORTS.md` before implementing a managed report.
|
|
@@ -4,8 +4,6 @@ This repository provides the `pam` CLI and runtime framework to build Data Plugi
|
|
|
4
4
|
|
|
5
5
|
This README is a practical, step-by-step guide you can follow to create and run a real service.
|
|
6
6
|
|
|
7
|
-
Current release target: **0.2.0**
|
|
8
|
-
|
|
9
7
|
**What you get**
|
|
10
8
|
|
|
11
9
|
- CLI to initialize a project and scaffold services
|
|
@@ -35,25 +33,26 @@ Current release target: **0.2.0**
|
|
|
35
33
|
|
|
36
34
|
**Prerequisites**
|
|
37
35
|
|
|
38
|
-
- Python 3.
|
|
39
|
-
- `
|
|
36
|
+
- Python 3.12
|
|
37
|
+
- `uv` (recommended) or `pip`
|
|
40
38
|
|
|
41
39
|
---
|
|
42
40
|
|
|
43
41
|
**Install**
|
|
44
|
-
|
|
42
|
+
Recommended installation:
|
|
45
43
|
|
|
46
44
|
```bash
|
|
47
45
|
mkdir my_data_plugin
|
|
48
46
|
cd my_data_plugin
|
|
49
|
-
|
|
50
|
-
source venv/bin/activate
|
|
47
|
+
uv tool install pam-python
|
|
51
48
|
```
|
|
52
49
|
|
|
53
|
-
|
|
50
|
+
Pip remains supported:
|
|
54
51
|
|
|
55
52
|
```bash
|
|
56
|
-
|
|
53
|
+
python3 -m venv venv
|
|
54
|
+
source venv/bin/activate
|
|
55
|
+
python -m pip install pam-python
|
|
57
56
|
```
|
|
58
57
|
|
|
59
58
|
---
|
|
@@ -66,23 +65,26 @@ rules and `REPORTS.md` for the managed-report public API and copyable examples.
|
|
|
66
65
|
pam init
|
|
67
66
|
```
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- keep
|
|
73
|
-
- merge
|
|
68
|
+
`pam init` asks you to select `uv` (default) or `pip`. A uv project contains
|
|
69
|
+
`pyproject.toml`, `.python-version`, and `uv.lock`; a pip project contains
|
|
70
|
+
`requirements.txt`. The two templates are independent and are never mixed.
|
|
74
71
|
|
|
75
|
-
|
|
72
|
+
Initialization only supports a new project directory and will not migrate or
|
|
73
|
+
overwrite an existing project.
|
|
76
74
|
|
|
77
75
|
---
|
|
78
76
|
|
|
79
77
|
**Create a Service**
|
|
80
|
-
Generate a service scaffold. Do not hand-create service templates.
|
|
81
78
|
|
|
82
79
|
```bash
|
|
83
80
|
pam new service rfm_segment
|
|
84
81
|
```
|
|
85
82
|
|
|
83
|
+
The generator asks you to select Polars (default) or Pandas. Polars services use
|
|
84
|
+
lazy Parquet processing. Pandas services also receive Parquet and install
|
|
85
|
+
`pandas` plus `pyarrow`. The selected direct dependencies are added to the
|
|
86
|
+
project automatically.
|
|
87
|
+
|
|
86
88
|
This creates a new folder (e.g. `rfm_segment/`) with:
|
|
87
89
|
|
|
88
90
|
- a service class (`RfmSegmentSvc.py`)
|
|
@@ -104,7 +106,8 @@ The runtime calls your service in two main phases.
|
|
|
104
106
|
2. `on_data_input`
|
|
105
107
|
|
|
106
108
|
- Called when CDP sends input files
|
|
107
|
-
- `req.input_files` contains ordered
|
|
109
|
+
- `req.input_files` contains ordered Parquet files
|
|
110
|
+
- `req.file_format` is the typed format sent by PAM
|
|
108
111
|
- Should also return quickly (use a thread if needed)
|
|
109
112
|
|
|
110
113
|
When your service is done:
|
|
@@ -132,7 +135,11 @@ Notes:
|
|
|
132
135
|
---
|
|
133
136
|
|
|
134
137
|
**Uploading Results in Batches**
|
|
135
|
-
|
|
138
|
+
Polars templates pass `LazyFrame` results directly to `_upload_result(...)`, which
|
|
139
|
+
streams them to the CSV upload boundary. Do not collect or convert to Pandas first.
|
|
140
|
+
|
|
141
|
+
For eager Polars or Pandas DataFrames, use the batch uploader to handle chunking
|
|
142
|
+
and flushing automatically.
|
|
136
143
|
|
|
137
144
|
Recommended usage:
|
|
138
145
|
|
|
@@ -152,6 +159,7 @@ Notes:
|
|
|
152
159
|
- `options` may be passed to `upload(...)` and are forwarded to `_upload_result`.
|
|
153
160
|
- Complete batches upload immediately; `flush()` sends the remaining rows.
|
|
154
161
|
- `get_status()` returns buffered rows, uploaded rows, and uploaded batch counts per stream.
|
|
162
|
+
- `ResultBatchUploader` intentionally rejects Polars `LazyFrame`; upload it directly.
|
|
155
163
|
|
|
156
164
|
---
|
|
157
165
|
|
|
@@ -188,7 +196,8 @@ Important rules:
|
|
|
188
196
|
The generated `main.py` runs the Flask server.
|
|
189
197
|
|
|
190
198
|
```bash
|
|
191
|
-
python main.py
|
|
199
|
+
uv run python main.py # uv project
|
|
200
|
+
python main.py # pip project
|
|
192
201
|
```
|
|
193
202
|
|
|
194
203
|
By default it binds to `0.0.0.0:8000`. You can override with:
|
|
@@ -201,9 +210,13 @@ export SERVER_PORT=8000
|
|
|
201
210
|
---
|
|
202
211
|
|
|
203
212
|
**Testing a Service**
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
213
|
+
For uv projects, use one cross-platform command:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
uv run python -m unittest discover -s rfm_segment -p "test_*.py"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Pip projects include shell-specific scripts:
|
|
207
220
|
|
|
208
221
|
macOS/Linux:
|
|
209
222
|
|
|
@@ -248,20 +261,23 @@ After `pam init` and one service:
|
|
|
248
261
|
├── AGENT.md
|
|
249
262
|
├── REPORTS.md
|
|
250
263
|
├── Dockerfile
|
|
264
|
+
├── pyproject.toml
|
|
265
|
+
├── uv.lock
|
|
266
|
+
├── .python-version
|
|
251
267
|
├── rfm_segment/
|
|
252
268
|
│ ├── RfmSegmentSvc.py
|
|
253
269
|
│ ├── functions.py
|
|
254
270
|
│ ├── service.yaml
|
|
255
271
|
│ └── test_rfm_segment.py
|
|
256
|
-
|
|
257
|
-
└── run_unit_test.sh
|
|
272
|
+
└── .pam-project
|
|
258
273
|
```
|
|
259
274
|
|
|
260
275
|
---
|
|
261
276
|
|
|
262
277
|
**Troubleshooting**
|
|
263
278
|
|
|
264
|
-
- If `pam`
|
|
279
|
+
- If `pam` is missing, verify the uv tool installation or activate the pip virtualenv.
|
|
280
|
+
- If uv initialization fails, verify `uv` is on `PATH` and package indexes are reachable.
|
|
265
281
|
- If `pam new service` fails, confirm the service name is provided.
|
|
266
282
|
- If temp cleanup is too frequent or too slow, adjust `TEMP_CLEAN_INTERVAL_HOURS` and `TEMP_CLEAN_DAYS`.
|
|
267
283
|
|
|
@@ -272,5 +288,6 @@ After `pam init` and one service:
|
|
|
272
288
|
- Implement your logic in `functions.py`.
|
|
273
289
|
- Wire it into `on_start` and `on_data_input` in your service class.
|
|
274
290
|
- Use the temp utilities to write intermediate files.
|
|
275
|
-
-
|
|
291
|
+
- Keep Polars transformations lazy and upload the resulting `LazyFrame` directly.
|
|
292
|
+
- Use `ResultBatchUploader` only for eager Polars/Pandas frames that need row batching.
|
|
276
293
|
- Read `REPORTS.md` before implementing a managed report.
|