comhom-sdk 0.1.0__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,315 @@
1
+ Metadata-Version: 2.4
2
+ Name: comhom-sdk
3
+ Version: 0.1.0
4
+ Summary: The official SDK for integrating homelessness data into the Comhom Platform.
5
+ Author: Socialit
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: jsonschema~=4.25.1
13
+ Dynamic: author
14
+ Dynamic: classifier
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: license-file
18
+ Dynamic: requires-dist
19
+ Dynamic: requires-python
20
+ Dynamic: summary
21
+
22
+ # Uploading Answers with `comhom_sdk.py`
23
+
24
+ This guide is for end users who want to upload answer data to Comhom using a file.
25
+
26
+ Script location: `sdk/comhom_sdk.py`
27
+
28
+ ## Before you start
29
+
30
+ You need:
31
+
32
+ - Python 3.10+
33
+ - A valid API key with permission to upload answers
34
+ - A data file in `.json` or `.csv` format
35
+
36
+ If needed, install dependency:
37
+
38
+ ```bash
39
+ pip install jsonschema
40
+ ```
41
+
42
+ When you generate an API key on the platform, it is downloaded as `comhom.key`. The SDK uses that filename by default for `--api-key-file`.
43
+
44
+ Your organization is resolved automatically from the API key — you do not pass an organization ID to the SDK.
45
+
46
+ ## 1) Prepare your API key file
47
+
48
+ Create a plain text file (for example `comhom.key`) that contains only your key:
49
+
50
+ ```text
51
+ your-api-key-here
52
+ ```
53
+
54
+ ## 2) Prepare your answers file
55
+
56
+ You can use **JSON** or **CSV**.
57
+
58
+ Each row is one answer. Required fields:
59
+
60
+ | Field | Description |
61
+ |---|---|
62
+ | `respondent_code` | Stable, pseudonymous identifier for the respondent |
63
+ | `question_code` | Code of the question being answered |
64
+ | `value` | The answer (format depends on question type; see below) |
65
+ | `answered_at` | Date the answer was collected (`YYYY-MM-DD`) |
66
+ | `consent_signed` | Whether the respondent consented to data use (`true` / `false`) |
67
+
68
+ ### Question codes and values
69
+
70
+ Valid `question_code` values come from the Comhom question catalogue. Examples from the platform fixtures:
71
+
72
+ | `question_code` | Type | Example `value` |
73
+ |---|---|---|
74
+ | `sex_gender` | Single choice | `cisgender_woman` |
75
+ | `age` | Single choice | `25_34` |
76
+ | `nationality` | Single choice | `national_country` |
77
+ | `A2` | Date | `2026-01-10` |
78
+ | `A4` | Single choice | `programme_completion` |
79
+ | `A5` | Program | `housing_first` (your org's program code) |
80
+ | `A6` | Multiple choice | `["cm", "hn"]` |
81
+
82
+ **Value formats:**
83
+
84
+ - **Single choice** — one option code (for example `sex_gender` → `cisgender_woman`, or `age` → `25_34`).
85
+ - **Multiple choice** — a list of option codes (for example `A6` → `["cm", "hn"]`).
86
+ - **Date** — `YYYY-MM-DD` (for example `A2` → `2026-01-10`).
87
+ - **Program (A5)** — a program `code` from your organization (created on the platform first; not a global option).
88
+
89
+ Only rows with `consent_signed: true` are loaded.
90
+
91
+ ### JSON format
92
+
93
+ Use either:
94
+
95
+ - A top-level array of answers, or
96
+ - An object with an `answers` array
97
+
98
+ Example — one beneficiary with micro- and meso-variable answers:
99
+
100
+ ```json
101
+ [
102
+ {
103
+ "respondent_code": "hash_7f3a9c2e",
104
+ "question_code": "sex_gender",
105
+ "answered_at": "2026-06-15",
106
+ "consent_signed": true,
107
+ "value": "cisgender_woman"
108
+ },
109
+ {
110
+ "respondent_code": "hash_7f3a9c2e",
111
+ "question_code": "age",
112
+ "answered_at": "2026-06-15",
113
+ "consent_signed": true,
114
+ "value": "25_34"
115
+ },
116
+ {
117
+ "respondent_code": "hash_7f3a9c2e",
118
+ "question_code": "A2",
119
+ "answered_at": "2026-06-15",
120
+ "consent_signed": true,
121
+ "value": "2026-01-10"
122
+ },
123
+ {
124
+ "respondent_code": "hash_7f3a9c2e",
125
+ "question_code": "A5",
126
+ "answered_at": "2026-06-15",
127
+ "consent_signed": true,
128
+ "value": "housing_first"
129
+ },
130
+ {
131
+ "respondent_code": "hash_7f3a9c2e",
132
+ "question_code": "A6",
133
+ "answered_at": "2026-06-15",
134
+ "consent_signed": true,
135
+ "value": ["cm", "hn"]
136
+ }
137
+ ]
138
+ ```
139
+
140
+ ### CSV format
141
+
142
+ Required columns:
143
+
144
+ - `respondent_code`
145
+ - `question_code`
146
+ - `answered_at`
147
+ - `consent_signed`
148
+ - `value`
149
+
150
+ `answered_at` is the collection/snapshot date for each answer. If your source system does not track per-answer timestamps, set one date for the whole export.
151
+
152
+ Upload behavior:
153
+
154
+ - Duplicate rows in the same file for the same beneficiary/question/date: the **last row wins**.
155
+ - Same value as the latest known snapshot on or before that date: the row is **skipped** (safe to re-upload).
156
+ - Same date with a changed value: the existing snapshot is **updated**.
157
+ - New date with a changed value: a new history row is **created**.
158
+
159
+ Example:
160
+
161
+ ```csv
162
+ respondent_code,question_code,answered_at,consent_signed,value
163
+ hash_7f3a9c2e,sex_gender,2026-06-15,true,cisgender_woman
164
+ hash_7f3a9c2e,age,2026-06-15,true,25_34
165
+ hash_7f3a9c2e,A2,2026-06-15,true,2026-01-10
166
+ hash_7f3a9c2e,A5,2026-06-15,true,housing_first
167
+ hash_7f3a9c2e,A6,2026-06-15,true,"[""cm"",""hn""]"
168
+ ```
169
+
170
+ ## 3) Run the upload
171
+
172
+ ```bash
173
+ python3 sdk/comhom_sdk.py upload \
174
+ --input-file "/path/to/answers.json" \
175
+ --api-key-file comhom.key
176
+ ```
177
+
178
+ If your input is CSV, just change `--input-file` to the CSV path.
179
+
180
+ By default, uploads go to **sandbox**. Add `--production` to target production.
181
+
182
+ ## Generating synthetic answers (optional)
183
+
184
+ You can generate synthetic answers to a file using the platform's answer upload JSON schema. The SDK fetches the org-specific schema automatically using your API key. Generation is separate from upload: write a file with `generate`, then upload it with `upload`.
185
+
186
+ ```bash
187
+ python3 sdk/comhom_sdk.py generate \
188
+ --total-answers 1000 \
189
+ --respondent-count 20 \
190
+ --output-file "/path/to/synthetic_answers.json" \
191
+ --api-key-file comhom.key
192
+ ```
193
+
194
+ To upload the generated file:
195
+
196
+ ```bash
197
+ python3 sdk/comhom_sdk.py upload \
198
+ --input-file "/path/to/synthetic_answers.json" \
199
+ --api-key-file comhom.key
200
+ ```
201
+
202
+ The output format is determined by the extension:
203
+
204
+ - `.json` -> JSON array
205
+ - `.csv` -> CSV with the required columns
206
+
207
+ ## Command options
208
+
209
+ ### `upload`
210
+
211
+ | Option | Short | Required | Description |
212
+ |---|---|---|---|
213
+ | `--input-file` | `-i` | Yes | Path to `.json` or `.csv` file |
214
+ | `--api-key-file` | `-k` | No | Path to API key file (default: `comhom.key`) |
215
+ | `--production` | `-p` | No | Upload to production (default is sandbox) |
216
+ | `--batch-size` | `-b` | No | Answers per request (default `500`) |
217
+
218
+ ### `generate`
219
+
220
+ | Option | Short | Required | Description |
221
+ |---|---|---|---|
222
+ | `--total-answers` | `-n` | Yes | Number of synthetic answers to generate |
223
+ | `--output-file` | `-o` | Yes | Path to write `.json` or `.csv` output |
224
+ | `--respondent-count` | `-c` | No | Number of respondent codes to use (default `1`) |
225
+ | `--respondent-prefix` | `-p` | No | Prefix for respondent codes (default `R`) |
226
+ | `--answered-at` | `-a` | No | Fixed answered date (`YYYY-MM-DD`) for all answers |
227
+ | `--days-back` | `-d` | No | If `--answered-at` is not set, random date within last N days (default `365`; use `0` for today only) |
228
+ | `--seed` | `-s` | No | Seed for deterministic generation |
229
+ | `--api-key-file` | `-k` | No | Path to API key file (default: `comhom.key`) |
230
+
231
+ ### `validate`
232
+
233
+ | Option | Short | Required | Description |
234
+ |---|---|---|---|
235
+ | `--input-file` | `-i` | Yes | Path to `.json` or `.csv` file |
236
+ | `--api-key-file` | `-k` | No | Path to API key file (default: `comhom.key`) |
237
+ | `--errors-file` | `-e` | No | Write all validation errors to a CSV file when validation fails |
238
+
239
+ ### `delete`
240
+
241
+ | Option | Short | Required | Description |
242
+ |---|---|---|---|
243
+ | `--respondent-code` | `-r` | Yes | Beneficiary/respondent code whose answers to delete |
244
+ | `--api-key-file` | `-k` | No | Path to API key file (default: `comhom.key`) |
245
+ | `--production` | `-p` | No | Delete production data instead of sandbox (default is sandbox) |
246
+
247
+ ## What the script does
248
+
249
+ ### `upload`
250
+
251
+ 1. Read your API key from file
252
+ 2. Read and parse your JSON/CSV answers
253
+ 3. Download the current upload schema from the platform using your API key (includes org-specific enums such as A5 program codes)
254
+ 4. Validate your file locally before sending
255
+ 5. Upload answers in batches
256
+
257
+ ### `generate`
258
+
259
+ 1. Fetch the answer upload JSON schema from the platform using your API key
260
+ 2. Generate synthetic answers that conform to the schema
261
+ 3. Write them to a JSON or CSV file
262
+
263
+ ### `validate`
264
+
265
+ 1. Read and parse your JSON/CSV answers
266
+ 2. Download the current upload schema from the platform using your API key
267
+ 3. Validate every answer row locally without uploading
268
+
269
+ Example:
270
+
271
+ ```bash
272
+ python3 sdk/comhom_sdk.py validate \
273
+ --input-file "/path/to/answers.json" \
274
+ --api-key-file comhom.key \
275
+ --errors-file errors.csv
276
+ ```
277
+
278
+ ### `delete`
279
+
280
+ 1. Read your API key from file
281
+ 2. Resolve your organization from the API key
282
+ 3. Delete all answers for the given `respondent_code` in sandbox or production
283
+
284
+ Example:
285
+
286
+ ```bash
287
+ python3 sdk/comhom_sdk.py delete \
288
+ --respondent-code hash_7f3a9c2e \
289
+ --api-key-file comhom.key
290
+ ```
291
+
292
+ ## Success and errors
293
+
294
+ - On success, upload returns counts for `created`, `updated`, and `skipped` rows.
295
+ - On failure, you will see an error message and no further batches are sent.
296
+ - When `validate` fails, use `--errors-file` to export every error row for review.
297
+
298
+ Common issues:
299
+
300
+ - Wrong API key or no permission
301
+ - Missing required columns in CSV
302
+ - Invalid date format (must be `YYYY-MM-DD`)
303
+ - `consent_signed` not set to `true`
304
+ - Invalid `question_code` or option code for that question
305
+ - A5 `value` not matching a program code in your organization
306
+ - Extra/invalid fields that do not match schema
307
+
308
+ ## Notes
309
+
310
+ - By default, uploads go to sandbox.
311
+ - Use `--production` (or `-p`) to upload to or delete from production.
312
+ - The API key file defaults to `comhom.key` if `--api-key-file` is omitted.
313
+ - Client-side schema validation checks structure and required fields before upload.
314
+ - Question-specific `value` validation is finalized by the server during upload.
315
+ - Keep `comhom.key` out of source control.
@@ -0,0 +1,6 @@
1
+ comhom_sdk.py,sha256=dOZppbdpHpSY7C5qLUjR0-WPOMmDgQ6NzwaBPkeJwck,46711
2
+ comhom_sdk-0.1.0.dist-info/licenses/LICENSE,sha256=ssp_yhT70JjhePrSrWhsyqFuaByX_As-yXPQ5ryV8qk,1065
3
+ comhom_sdk-0.1.0.dist-info/METADATA,sha256=XpYd_vYS2uRDqpG9_8pzG9Q-rvLfz4GIqNmciAQhRjQ,9845
4
+ comhom_sdk-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
5
+ comhom_sdk-0.1.0.dist-info/top_level.txt,sha256=vncKMaRwJcNCh1m_YQfza50f07d4bqwX_bTSPwhdWM0,11
6
+ comhom_sdk-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Socialit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ comhom_sdk