pam-python 0.2.0__tar.gz → 0.2.2__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.
Files changed (116) hide show
  1. {pam_python-0.2.0/pam_python.egg-info → pam_python-0.2.2}/PKG-INFO +56 -60
  2. {pam_python-0.2.0 → pam_python-0.2.2}/README.md +50 -37
  3. {pam_python-0.2.0 → pam_python-0.2.2}/pam/__init__.py +1 -1
  4. pam_python-0.2.2/pam/cli.py +429 -0
  5. {pam_python-0.2.0 → pam_python-0.2.2}/pam/models/request_command.py +4 -0
  6. pam_python-0.2.2/pam/request_file_format.py +14 -0
  7. pam_python-0.2.2/pam/result_batch_uploader.py +227 -0
  8. {pam_python-0.2.0 → pam_python-0.2.2}/pam/server.py +22 -2
  9. {pam_python-0.2.0 → pam_python-0.2.2}/pam/service.py +38 -25
  10. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/AGENT.md +48 -68
  11. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/REPORTS.md +2 -2
  12. pam_python-0.2.2/pam/templates/init/dockerignore.tmpl +6 -0
  13. pam_python-0.2.2/pam/templates/project/pip/Dockerfile +16 -0
  14. {pam_python-0.2.0/pam/templates/init → pam_python-0.2.2/pam/templates/project/pip}/requirements.txt +0 -2
  15. pam_python-0.2.2/pam/templates/project/uv/Dockerfile +20 -0
  16. pam_python-0.2.2/pam/templates/project/uv/pyproject.toml +12 -0
  17. pam_python-0.2.2/pam/templates/project/uv/python-version +1 -0
  18. pam_python-0.2.2/pam/templates/service/pandas/functions.tmpl +13 -0
  19. {pam_python-0.2.0/pam/templates/service → pam_python-0.2.2/pam/templates/service/pandas}/service.test.tmpl +31 -46
  20. pam_python-0.2.2/pam/templates/service/pandas/service_class.tmpl +65 -0
  21. pam_python-0.2.2/pam/templates/service/polars/functions.tmpl +11 -0
  22. pam_python-0.2.2/pam/templates/service/polars/service.test.tmpl +122 -0
  23. pam_python-0.2.2/pam/templates/service/polars/service_class.tmpl +59 -0
  24. {pam_python-0.2.0 → pam_python-0.2.2}/pam/tester_task.py +22 -7
  25. {pam_python-0.2.0 → pam_python-0.2.2}/pam/utils.py +2 -4
  26. {pam_python-0.2.0 → pam_python-0.2.2/pam_python.egg-info}/PKG-INFO +56 -60
  27. {pam_python-0.2.0 → pam_python-0.2.2}/pam_python.egg-info/SOURCES.txt +14 -7
  28. pam_python-0.2.2/pam_python.egg-info/requires.txt +3 -0
  29. pam_python-0.2.2/pyproject.toml +54 -0
  30. pam_python-0.2.2/tests/test_cli_templates.py +185 -0
  31. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_result_batch_uploader.py +28 -2
  32. pam_python-0.2.2/tests/test_service_dataframe_output.py +41 -0
  33. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_sqlite_download_v2.py +21 -0
  34. pam_python-0.2.0/pam/cli.py +0 -226
  35. pam_python-0.2.0/pam/request_file_format.py +0 -5
  36. pam_python-0.2.0/pam/result_batch_uploader.py +0 -179
  37. pam_python-0.2.0/pam/templates/docker/Dockerfile +0 -21
  38. pam_python-0.2.0/pam/templates/init/dockerignore.tmpl +0 -4
  39. pam_python-0.2.0/pam/templates/service/functions.tmpl +0 -22
  40. pam_python-0.2.0/pam/templates/service/service_class.tmpl +0 -81
  41. pam_python-0.2.0/pam_python.egg-info/requires.txt +0 -9
  42. pam_python-0.2.0/setup.py +0 -43
  43. pam_python-0.2.0/tests/test_cli_templates.py +0 -78
  44. {pam_python-0.2.0 → pam_python-0.2.2}/LICENSE.txt +0 -0
  45. {pam_python-0.2.0 → pam_python-0.2.2}/pam/api.py +0 -0
  46. {pam_python-0.2.0 → pam_python-0.2.2}/pam/interface_task_manager.py +0 -0
  47. {pam_python-0.2.0 → pam_python-0.2.2}/pam/logger.py +0 -0
  48. {pam_python-0.2.0 → pam_python-0.2.2}/pam/models/__init__.py +0 -0
  49. {pam_python-0.2.0 → pam_python-0.2.2}/pam/models/sqlite_download.py +0 -0
  50. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/__init__.py +0 -0
  51. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/area.py +0 -0
  52. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/axis.py +0 -0
  53. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/bar.py +0 -0
  54. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/box_plot.py +0 -0
  55. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/bubble.py +0 -0
  56. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/candlestick.py +0 -0
  57. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/collection.py +0 -0
  58. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/definition.py +0 -0
  59. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/donut.py +0 -0
  60. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/errors.py +0 -0
  61. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/fields.py +0 -0
  62. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/heatmap.py +0 -0
  63. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/line.py +0 -0
  64. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/manager.py +0 -0
  65. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/metric.py +0 -0
  66. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/pie.py +0 -0
  67. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/polar_area.py +0 -0
  68. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/radar.py +0 -0
  69. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/radial_bar.py +0 -0
  70. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/range_area.py +0 -0
  71. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/range_bar.py +0 -0
  72. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/range_transform.py +0 -0
  73. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/record.py +0 -0
  74. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/report.py +0 -0
  75. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/scatter.py +0 -0
  76. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/schema.py +0 -0
  77. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/store.py +0 -0
  78. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/table.py +0 -0
  79. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/transport.py +0 -0
  80. {pam_python-0.2.0 → pam_python-0.2.2}/pam/reports/treemap.py +0 -0
  81. {pam_python-0.2.0 → pam_python-0.2.2}/pam/sqlite.py +0 -0
  82. {pam_python-0.2.0 → pam_python-0.2.2}/pam/task_manager.py +0 -0
  83. {pam_python-0.2.0 → pam_python-0.2.2}/pam/temp_file_utils.py +0 -0
  84. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/buildcmd/pamb +0 -0
  85. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/buildcmd/pamb-base.sh +0 -0
  86. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/gitignore.tmpl +0 -0
  87. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/main.tmpl +0 -0
  88. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/pylintrc.tmpl +0 -0
  89. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/run_unit_test.bat +0 -0
  90. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/run_unit_test.ps1 +0 -0
  91. {pam_python-0.2.0 → pam_python-0.2.2}/pam/templates/init/run_unit_test.sh +0 -0
  92. {pam_python-0.2.0/pam/templates/service → pam_python-0.2.2/pam/templates/service/common}/service.yaml +1 -1
  93. {pam_python-0.2.0 → pam_python-0.2.2}/pam_python.egg-info/dependency_links.txt +0 -0
  94. {pam_python-0.2.0 → pam_python-0.2.2}/pam_python.egg-info/entry_points.txt +0 -0
  95. {pam_python-0.2.0 → pam_python-0.2.2}/pam_python.egg-info/top_level.txt +0 -0
  96. {pam_python-0.2.0 → pam_python-0.2.2}/setup.cfg +0 -0
  97. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_range_transform.py +0 -0
  98. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_report_store.py +0 -0
  99. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_area_report.py +0 -0
  100. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_bar_report.py +0 -0
  101. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_box_plot_report.py +0 -0
  102. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_bubble_report.py +0 -0
  103. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_candlestick_report.py +0 -0
  104. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_donut_report.py +0 -0
  105. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_heatmap_report.py +0 -0
  106. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_line_report.py +0 -0
  107. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_metric_report.py +0 -0
  108. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_pie_report.py +0 -0
  109. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_polar_area_report.py +0 -0
  110. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_radar_report.py +0 -0
  111. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_radial_bar_report.py +0 -0
  112. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_range_area_report.py +0 -0
  113. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_range_bar_report.py +0 -0
  114. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_scatter_report.py +0 -0
  115. {pam_python-0.2.0 → pam_python-0.2.2}/tests/test_typed_table_report.py +0 -0
  116. {pam_python-0.2.0 → pam_python-0.2.2}/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.0
3
+ Version: 0.2.2
4
4
  Summary: Pam Python Library
5
- Home-page: https://github.com/heart/pam-python
6
- Author: Narongrit Kanhanoi
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.9
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: >=3.9
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: gunicorn>=23.0.0
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,54 +53,54 @@ Current release target: **0.2.0**
72
53
 
73
54
  **Prerequisites**
74
55
 
75
- - Python 3.9+
76
- - `pip` and a working virtual environment
56
+ - Python 3.12
57
+ - `uv` (recommended) or `pip`
77
58
 
78
59
  ---
79
60
 
80
- **Install**
81
- Create a project folder and a virtual environment.
61
+ **Create a uv project**
62
+
63
+ Install PAM inside each project instead of installing the CLI globally:
82
64
 
83
65
  ```bash
84
66
  mkdir my_data_plugin
85
67
  cd my_data_plugin
86
- python3 -m venv venv
87
- source venv/bin/activate
68
+ uv init --python 3.12
69
+ uv add pam-python
70
+ uv run pam init
88
71
  ```
89
72
 
90
- Install the framework:
73
+ `pam init` recognizes a fresh uv project, keeps its uv configuration, and adds
74
+ the PAM scaffold. It refuses projects whose generated source files have already
75
+ been edited.
91
76
 
92
- ```bash
93
- pip install pam-python
94
- ```
95
-
96
- ---
97
-
98
- **Initialize a Project**
99
- This creates a runnable project with templates, including `AGENT.md` for runtime
100
- rules and `REPORTS.md` for the managed-report public API and copyable examples.
77
+ Pip remains supported for new projects that do not use uv:
101
78
 
102
79
  ```bash
80
+ mkdir my_data_plugin
81
+ cd my_data_plugin
82
+ python3 -m venv venv
83
+ source venv/bin/activate
84
+ python -m pip install pam-python
103
85
  pam init
104
86
  ```
105
87
 
106
- When `requirements.txt` already exists, you will be prompted to choose how to proceed:
107
-
108
- - overwrite
109
- - keep
110
- - merge
111
-
112
- `pam init` now writes a project baseline `requirements.txt`. It pins `pam-python` to the scaffold version and includes core runtime/test dependencies used by the generated project. It does not copy the current machine's `pip freeze`.
88
+ When run in an empty directory, `pam init` still asks whether to create a uv or
89
+ pip project. PAM never migrates an existing application.
113
90
 
114
91
  ---
115
92
 
116
93
  **Create a Service**
117
- Generate a service scaffold. Do not hand-create service templates.
118
94
 
119
95
  ```bash
120
- pam new service rfm_segment
96
+ uv run pam new service rfm_segment
121
97
  ```
122
98
 
99
+ The generator asks you to select Polars (default) or Pandas. Polars services use
100
+ lazy Parquet processing. Pandas services also receive Parquet and install
101
+ `pandas` plus `pyarrow`. The selected direct dependencies are added to the
102
+ project automatically.
103
+
123
104
  This creates a new folder (e.g. `rfm_segment/`) with:
124
105
 
125
106
  - a service class (`RfmSegmentSvc.py`)
@@ -141,7 +122,8 @@ The runtime calls your service in two main phases.
141
122
  2. `on_data_input`
142
123
 
143
124
  - Called when CDP sends input files
144
- - `req.input_files` contains ordered CSV files
125
+ - `req.input_files` contains ordered Parquet files
126
+ - `req.file_format` is the typed format sent by PAM
145
127
  - Should also return quickly (use a thread if needed)
146
128
 
147
129
  When your service is done:
@@ -169,7 +151,11 @@ Notes:
169
151
  ---
170
152
 
171
153
  **Uploading Results in Batches**
172
- If your service produces too many rows (or too few per event), use the batch uploader to handle chunking and flushing automatically.
154
+ Polars templates pass `LazyFrame` results directly to `_upload_result(...)`, which
155
+ streams them to the CSV upload boundary. Do not collect or convert to Pandas first.
156
+
157
+ For eager Polars or Pandas DataFrames, use the batch uploader to handle chunking
158
+ and flushing automatically.
173
159
 
174
160
  Recommended usage:
175
161
 
@@ -189,6 +175,7 @@ Notes:
189
175
  - `options` may be passed to `upload(...)` and are forwarded to `_upload_result`.
190
176
  - Complete batches upload immediately; `flush()` sends the remaining rows.
191
177
  - `get_status()` returns buffered rows, uploaded rows, and uploaded batch counts per stream.
178
+ - `ResultBatchUploader` intentionally rejects Polars `LazyFrame`; upload it directly.
192
179
 
193
180
  ---
194
181
 
@@ -225,7 +212,8 @@ Important rules:
225
212
  The generated `main.py` runs the Flask server.
226
213
 
227
214
  ```bash
228
- python main.py
215
+ uv run python main.py # uv project
216
+ python main.py # pip project
229
217
  ```
230
218
 
231
219
  By default it binds to `0.0.0.0:8000`. You can override with:
@@ -238,9 +226,13 @@ export SERVER_PORT=8000
238
226
  ---
239
227
 
240
228
  **Testing a Service**
241
- Run tests through the generated script for your current shell. This keeps the
242
- active terminal's Python environment and project context instead of launching
243
- test discovery through the `pam` CLI.
229
+ For uv projects, use one cross-platform command:
230
+
231
+ ```bash
232
+ uv run python -m unittest discover -s rfm_segment -p "test_*.py"
233
+ ```
234
+
235
+ Pip projects include shell-specific scripts:
244
236
 
245
237
  macOS/Linux:
246
238
 
@@ -285,20 +277,23 @@ After `pam init` and one service:
285
277
  ├── AGENT.md
286
278
  ├── REPORTS.md
287
279
  ├── Dockerfile
280
+ ├── pyproject.toml
281
+ ├── uv.lock
282
+ ├── .python-version
288
283
  ├── rfm_segment/
289
284
  │ ├── RfmSegmentSvc.py
290
285
  │ ├── functions.py
291
286
  │ ├── service.yaml
292
287
  │ └── test_rfm_segment.py
293
- ├── requirements.txt
294
- └── run_unit_test.sh
288
+ └── .pam-project
295
289
  ```
296
290
 
297
291
  ---
298
292
 
299
293
  **Troubleshooting**
300
294
 
301
- - If `pam` command is missing, ensure your virtualenv is activated.
295
+ - If `pam` is missing, verify the uv tool installation or activate the pip virtualenv.
296
+ - If uv initialization fails, verify `uv` is on `PATH` and package indexes are reachable.
302
297
  - If `pam new service` fails, confirm the service name is provided.
303
298
  - If temp cleanup is too frequent or too slow, adjust `TEMP_CLEAN_INTERVAL_HOURS` and `TEMP_CLEAN_DAYS`.
304
299
 
@@ -309,5 +304,6 @@ After `pam init` and one service:
309
304
  - Implement your logic in `functions.py`.
310
305
  - Wire it into `on_start` and `on_data_input` in your service class.
311
306
  - Use the temp utilities to write intermediate files.
312
- - Use `ResultBatchUploader` to return ordinary output to CDP.
307
+ - Keep Polars transformations lazy and upload the resulting `LazyFrame` directly.
308
+ - Use `ResultBatchUploader` only for eager Polars/Pandas frames that need row batching.
313
309
  - 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,54 +33,54 @@ Current release target: **0.2.0**
35
33
 
36
34
  **Prerequisites**
37
35
 
38
- - Python 3.9+
39
- - `pip` and a working virtual environment
36
+ - Python 3.12
37
+ - `uv` (recommended) or `pip`
40
38
 
41
39
  ---
42
40
 
43
- **Install**
44
- Create a project folder and a virtual environment.
41
+ **Create a uv project**
42
+
43
+ Install PAM inside each project instead of installing the CLI globally:
45
44
 
46
45
  ```bash
47
46
  mkdir my_data_plugin
48
47
  cd my_data_plugin
49
- python3 -m venv venv
50
- source venv/bin/activate
48
+ uv init --python 3.12
49
+ uv add pam-python
50
+ uv run pam init
51
51
  ```
52
52
 
53
- Install the framework:
53
+ `pam init` recognizes a fresh uv project, keeps its uv configuration, and adds
54
+ the PAM scaffold. It refuses projects whose generated source files have already
55
+ been edited.
54
56
 
55
- ```bash
56
- pip install pam-python
57
- ```
58
-
59
- ---
60
-
61
- **Initialize a Project**
62
- This creates a runnable project with templates, including `AGENT.md` for runtime
63
- rules and `REPORTS.md` for the managed-report public API and copyable examples.
57
+ Pip remains supported for new projects that do not use uv:
64
58
 
65
59
  ```bash
60
+ mkdir my_data_plugin
61
+ cd my_data_plugin
62
+ python3 -m venv venv
63
+ source venv/bin/activate
64
+ python -m pip install pam-python
66
65
  pam init
67
66
  ```
68
67
 
69
- When `requirements.txt` already exists, you will be prompted to choose how to proceed:
70
-
71
- - overwrite
72
- - keep
73
- - merge
74
-
75
- `pam init` now writes a project baseline `requirements.txt`. It pins `pam-python` to the scaffold version and includes core runtime/test dependencies used by the generated project. It does not copy the current machine's `pip freeze`.
68
+ When run in an empty directory, `pam init` still asks whether to create a uv or
69
+ pip project. PAM never migrates an existing application.
76
70
 
77
71
  ---
78
72
 
79
73
  **Create a Service**
80
- Generate a service scaffold. Do not hand-create service templates.
81
74
 
82
75
  ```bash
83
- pam new service rfm_segment
76
+ uv run pam new service rfm_segment
84
77
  ```
85
78
 
79
+ The generator asks you to select Polars (default) or Pandas. Polars services use
80
+ lazy Parquet processing. Pandas services also receive Parquet and install
81
+ `pandas` plus `pyarrow`. The selected direct dependencies are added to the
82
+ project automatically.
83
+
86
84
  This creates a new folder (e.g. `rfm_segment/`) with:
87
85
 
88
86
  - a service class (`RfmSegmentSvc.py`)
@@ -104,7 +102,8 @@ The runtime calls your service in two main phases.
104
102
  2. `on_data_input`
105
103
 
106
104
  - Called when CDP sends input files
107
- - `req.input_files` contains ordered CSV files
105
+ - `req.input_files` contains ordered Parquet files
106
+ - `req.file_format` is the typed format sent by PAM
108
107
  - Should also return quickly (use a thread if needed)
109
108
 
110
109
  When your service is done:
@@ -132,7 +131,11 @@ Notes:
132
131
  ---
133
132
 
134
133
  **Uploading Results in Batches**
135
- If your service produces too many rows (or too few per event), use the batch uploader to handle chunking and flushing automatically.
134
+ Polars templates pass `LazyFrame` results directly to `_upload_result(...)`, which
135
+ streams them to the CSV upload boundary. Do not collect or convert to Pandas first.
136
+
137
+ For eager Polars or Pandas DataFrames, use the batch uploader to handle chunking
138
+ and flushing automatically.
136
139
 
137
140
  Recommended usage:
138
141
 
@@ -152,6 +155,7 @@ Notes:
152
155
  - `options` may be passed to `upload(...)` and are forwarded to `_upload_result`.
153
156
  - Complete batches upload immediately; `flush()` sends the remaining rows.
154
157
  - `get_status()` returns buffered rows, uploaded rows, and uploaded batch counts per stream.
158
+ - `ResultBatchUploader` intentionally rejects Polars `LazyFrame`; upload it directly.
155
159
 
156
160
  ---
157
161
 
@@ -188,7 +192,8 @@ Important rules:
188
192
  The generated `main.py` runs the Flask server.
189
193
 
190
194
  ```bash
191
- python main.py
195
+ uv run python main.py # uv project
196
+ python main.py # pip project
192
197
  ```
193
198
 
194
199
  By default it binds to `0.0.0.0:8000`. You can override with:
@@ -201,9 +206,13 @@ export SERVER_PORT=8000
201
206
  ---
202
207
 
203
208
  **Testing a Service**
204
- Run tests through the generated script for your current shell. This keeps the
205
- active terminal's Python environment and project context instead of launching
206
- test discovery through the `pam` CLI.
209
+ For uv projects, use one cross-platform command:
210
+
211
+ ```bash
212
+ uv run python -m unittest discover -s rfm_segment -p "test_*.py"
213
+ ```
214
+
215
+ Pip projects include shell-specific scripts:
207
216
 
208
217
  macOS/Linux:
209
218
 
@@ -248,20 +257,23 @@ After `pam init` and one service:
248
257
  ├── AGENT.md
249
258
  ├── REPORTS.md
250
259
  ├── Dockerfile
260
+ ├── pyproject.toml
261
+ ├── uv.lock
262
+ ├── .python-version
251
263
  ├── rfm_segment/
252
264
  │ ├── RfmSegmentSvc.py
253
265
  │ ├── functions.py
254
266
  │ ├── service.yaml
255
267
  │ └── test_rfm_segment.py
256
- ├── requirements.txt
257
- └── run_unit_test.sh
268
+ └── .pam-project
258
269
  ```
259
270
 
260
271
  ---
261
272
 
262
273
  **Troubleshooting**
263
274
 
264
- - If `pam` command is missing, ensure your virtualenv is activated.
275
+ - If `pam` is missing, verify the uv tool installation or activate the pip virtualenv.
276
+ - If uv initialization fails, verify `uv` is on `PATH` and package indexes are reachable.
265
277
  - If `pam new service` fails, confirm the service name is provided.
266
278
  - If temp cleanup is too frequent or too slow, adjust `TEMP_CLEAN_INTERVAL_HOURS` and `TEMP_CLEAN_DAYS`.
267
279
 
@@ -272,5 +284,6 @@ After `pam init` and one service:
272
284
  - Implement your logic in `functions.py`.
273
285
  - Wire it into `on_start` and `on_data_input` in your service class.
274
286
  - Use the temp utilities to write intermediate files.
275
- - Use `ResultBatchUploader` to return ordinary output to CDP.
287
+ - Keep Polars transformations lazy and upload the resulting `LazyFrame` directly.
288
+ - Use `ResultBatchUploader` only for eager Polars/Pandas frames that need row batching.
276
289
  - Read `REPORTS.md` before implementing a managed report.
@@ -1,3 +1,3 @@
1
1
  """PAM Data Plugin framework."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.2"