pylantir 0.2.3__py3-none-any.whl → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pylantir
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Summary: Python - DICOM Modality WorkList with Optional API
5
5
  Author-email: Milton Camacho <miltoncamachoicc@gmail.com>
6
6
  Requires-Python: >=3.11.1
@@ -21,6 +21,8 @@ Requires-Dist: uuid
21
21
  Requires-Dist: coloredlogs
22
22
  Requires-Dist: python-dotenv
23
23
  Requires-Dist: pandas
24
+ Requires-Dist: requests
25
+ Requires-Dist: pytz
24
26
  Requires-Dist: fastapi>=0.104.1 ; extra == "api"
25
27
  Requires-Dist: uvicorn[standard]>=0.24.0 ; extra == "api"
26
28
  Requires-Dist: passlib[bcrypt]==1.7.4 ; extra == "api"
@@ -46,6 +48,7 @@ Requires-Dist: pytest-runner ; extra == "test"
46
48
  Requires-Dist: pytest==7.3.1 ; extra == "test"
47
49
  Requires-Dist: pytest-github-actions-annotate-failures ; extra == "test"
48
50
  Requires-Dist: shellcheck-py==0.9.0.2 ; extra == "test"
51
+ Requires-Dist: responses>=0.23.0 ; extra == "test"
49
52
  Project-URL: Documentation, https://github.com/miltoncamacho/pylantir/tree/main#readme
50
53
  Project-URL: Source, https://github.com/miltoncamacho/pylantir
51
54
  Project-URL: Tracker, https://github.com/miltoncamacho/pylantir/issues
@@ -197,14 +200,16 @@ usage: pylantir [-h] [--AEtitle AETITLE] [--ip IP] [--port PORT] [--pylantir_con
197
200
  - **--ip IP**: IP/host address for the server
198
201
  - **--port PORT**: Port for the server
199
202
  - **--pylantir_config PYLANTIR_CONFIG**: Path to the configuration JSON file containing pylantir configs:
203
+ - **data_sources**: Array of data source configurations (recommended new format)
204
+ - Each source has: `name`, `type`, `enabled`, `sync_interval`, `operation_interval`, `config`, `field_mapping`
205
+ - **redcap2wl**: Legacy field mapping (deprecated, auto-converts to data_sources)
200
206
  - **allowed_aet**: List of allowed AE titles e.g. `["MRI_SCANNER", "MRI_SCANNER_2"]`
201
- - **site**: Site ID:string
207
+ - **site**: Site ID (legacy format, deprecated)
202
208
  - **protocol**: `{"site": "protocol_name", "mapping": "HIS/RIS mapping"}`
203
- - **redcap2wl**: Dictionary of REDCap fields to worklist fields mapping e.g., `{"redcap_field": "worklist_field"}`
204
209
  - **db_path**: Path to main worklist database e.g., `"/path/to/worklist.db"`
205
210
  - **users_db_path**: Optional path to users authentication database e.g., `"/path/to/users.db"`
206
- - **db_update_interval**: How often to reload the database e
207
- - **operation_interval**: What is the time range in a day in which the database will be updated e.g., `{"start_time":[hours,minutes],"end_time":[hours,minutes]}`
211
+ - **db_update_interval**: Legacy sync interval (deprecated, use sync_interval in data_sources)
212
+ - **operation_interval**: Legacy operation window (deprecated, use operation_interval in data_sources)
208
213
  - **--mpps_action {create,set}**: Action to perform for MPPS either create or set
209
214
  - **--mpps_status {COMPLETED,DISCONTINUED}**: Status to set for MPPS either COMPLETED or DISCONTINUED
210
215
  - **--callingAEtitle CALLINGAETITLE**: Calling AE Title for MPPS, it helps when the MWL is limited to only accept certain AE titles
@@ -213,40 +218,317 @@ usage: pylantir [-h] [--AEtitle AETITLE] [--ip IP] [--port PORT] [--pylantir_con
213
218
 
214
219
  ## Configuration JSON file
215
220
 
216
- As a default pylantir will try to read a JSON structured file with the following structure:
221
+ Pylantir supports a modular data sources configuration that allows you to connect to multiple data sources simultaneously.
222
+
223
+ ### New Data Sources Format (Recommended)
224
+
225
+ The new configuration format uses a `data_sources` array to define one or more data sources:
217
226
 
218
227
  ```json
219
228
  {
220
229
  "db_path": "/path/to/worklist.db",
221
230
  "users_db_path": "/path/to/users.db",
222
231
  "db_echo": "False",
223
- "db_update_interval": 60,
224
- "operation_interval": {"start_time": [0,0],"end_time": [23,59]},
225
232
  "allowed_aet": [],
233
+ "data_sources": [
234
+ {
235
+ "name": "main_redcap",
236
+ "type": "redcap",
237
+ "enabled": true,
238
+ "sync_interval": 60,
239
+ "operation_interval": {
240
+ "start_time": [0, 0],
241
+ "end_time": [23, 59]
242
+ },
243
+ "config": {
244
+ "site_id": "792",
245
+ "protocol": "BRAIN_MRI_3T"
246
+ },
247
+ "field_mapping": {
248
+ "study_id": "study_id",
249
+ "instrument": "redcap_repeat_instrument",
250
+ "session_id": "mri_instance",
251
+ "family_id": "family_id",
252
+ "youth_dob_y": "youth_dob_y",
253
+ "t1_date": "t1_date",
254
+ "demo_sex": "demo_sex",
255
+ "scheduled_date": "mri_date",
256
+ "scheduled_time": "mri_time",
257
+ "mri_wt_lbs": "patient_weight_lb",
258
+ "referring_physician": "referring_physician_name",
259
+ "performing_physician": "performing_physician",
260
+ "station_name": "station_name",
261
+ "status": "performed_procedure_step_status"
262
+ }
263
+ }
264
+ ],
265
+ "protocol": {
266
+ "792": "BRAIN_MRI_3T",
267
+ "mapping": "GEHC"
268
+ }
269
+ }
270
+ ```
271
+
272
+ **Data Source Configuration Fields:**
273
+
274
+ - **`name`**: Unique identifier for this data source (used in logs and database tracking)
275
+ - **`type`**: Data source type (currently supports `"redcap"`; extensible for future sources)
276
+ - **`enabled`**: Boolean to enable/disable this source without removing its configuration
277
+ - **`sync_interval`**: How often to sync data (in seconds)
278
+ - **`operation_interval`**: Time window when sync should occur (24-hour format)
279
+ - `start_time`: `[hours, minutes]` - Start of operation window
280
+ - `end_time`: `[hours, minutes]` - End of operation window
281
+ - **`config`**: Source-specific configuration
282
+ - For REDCap: `site_id`, `protocol`, and optional API credentials
283
+ - **`field_mapping`**: Maps source fields to DICOM worklist fields
284
+ - **`window_mode`** (Calpendo optional): `rolling` (default) or `daily`
285
+ - **`daily_window`** (Calpendo optional): `{"start_time": [h, m], "end_time": [h, m]}`
286
+
287
+ ### Multiple Data Sources Example
288
+
289
+ You can configure multiple data sources to sync simultaneously:
290
+
291
+ ```json
292
+ {
293
+ "db_path": "/path/to/worklist.db",
294
+ "data_sources": [
295
+ {
296
+ "name": "site_792_redcap",
297
+ "type": "redcap",
298
+ "enabled": true,
299
+ "sync_interval": 60,
300
+ "config": {
301
+ "site_id": "792",
302
+ "protocol": "BRAIN_MRI_3T"
303
+ },
304
+ "field_mapping": { "study_id": "study_id" }
305
+ },
306
+ {
307
+ "name": "site_793_redcap",
308
+ "type": "redcap",
309
+ "enabled": true,
310
+ "sync_interval": 120,
311
+ "config": {
312
+ "site_id": "793",
313
+ "protocol": "CARDIAC_MRI"
314
+ },
315
+ "field_mapping": { "patient_id": "patient_id" }
316
+ }
317
+ ]
318
+ }
319
+ ```
320
+
321
+ ## Calpendo Data Source Integration
322
+
323
+ Pylantir supports integration with Calpendo booking systems to automatically sync MRI/EEG scanner bookings into the DICOM worklist. This allows scanner operators to see scheduled bookings directly on their imaging equipment.
324
+
325
+ ### Prerequisites
326
+
327
+ Set up environment variables for Calpendo authentication:
328
+
329
+ ```bash
330
+ export CALPENDO_USERNAME=<your_calpendo_username>
331
+ export CALPENDO_PASSWORD=<your_calpendo_password>
332
+ ```
333
+
334
+ ### Minimal Configuration
335
+
336
+ ```json
337
+ {
338
+ "db_path": "/path/to/worklist.db",
339
+ "data_sources": [
340
+ {
341
+ "name": "calpendo_mri",
342
+ "type": "calpendo",
343
+ "enabled": true,
344
+ "sync_interval": 60,
345
+ "config": {
346
+ "base_url": "https://your-institution.calpendo.com",
347
+ "resources": ["3T Diagnostic", "EEG Lab"]
348
+ },
349
+ "field_mapping": {
350
+ "patient_id": {
351
+ "source_field": "title",
352
+ "_extract": {
353
+ "pattern": "^([A-Z0-9]+)_.*",
354
+ "group": 1
355
+ }
356
+ },
357
+ "patient_name": {
358
+ "source_field": "title",
359
+ "_extract": {
360
+ "pattern": "^[A-Z0-9]+_(.+)$",
361
+ "group": 1
362
+ }
363
+ },
364
+ "study_description": {
365
+ "source_field": "properties.project.formattedName",
366
+ "_extract": {
367
+ "pattern": "^([^(]+)",
368
+ "group": 1
369
+ }
370
+ },
371
+ "accession_number": "id"
372
+ }
373
+ }
374
+ ]
375
+ }
376
+ ```
377
+
378
+ ### Full Configuration with All Options
379
+
380
+ ```json
381
+ {
382
+ "name": "calpendo_scanners",
383
+ "type": "calpendo",
384
+ "enabled": true,
385
+ "sync_interval": 60,
386
+ "config": {
387
+ "base_url": "https://your-institution.calpendo.com",
388
+ "resources": ["3T Diagnostic", "EEG Lab", "Mock Scanner"],
389
+ "status_filter": "Approved",
390
+ "lookback_multiplier": 2,
391
+ "timezone": "America/Edmonton",
392
+ "resource_modality_mapping": {
393
+ "3T": "MR",
394
+ "EEG": "EEG",
395
+ "Mock": "OT"
396
+ }
397
+ },
398
+ "field_mapping": {
399
+ "patient_id": {
400
+ "source_field": "title",
401
+ "_extract": {
402
+ "pattern": "^([A-Z0-9]+)_.*",
403
+ "group": 1
404
+ }
405
+ },
406
+ "patient_name": {
407
+ "source_field": "title",
408
+ "_extract": {
409
+ "pattern": "^[A-Z0-9]+_(.+)$",
410
+ "group": 1
411
+ }
412
+ },
413
+ "study_description": {
414
+ "source_field": "properties.project.formattedName",
415
+ "_extract": {
416
+ "pattern": "^([^(]+)",
417
+ "group": 1
418
+ }
419
+ },
420
+ "accession_number": "id",
421
+ "study_instance_uid": "id"
422
+ }
423
+ }
424
+ ```
425
+
426
+ **Calpendo Configuration Fields:**
427
+
428
+ - **`base_url`**: Calpendo server URL (e.g., `https://your-institution.calpendo.com`)
429
+ - **`resources`**: Array of resource names to sync (e.g., scanner names)
430
+ - **`status_filter`** (optional): Only sync bookings with this status (e.g., `"Approved"`)
431
+ - **`lookback_multiplier`** (optional, default: 2): Rolling window multiplier for incremental sync
432
+ - **`timezone`** (optional, default: `"America/Edmonton"`): Timezone for booking timestamps
433
+ - **`resource_modality_mapping`** (optional): Map resource names to DICOM modality codes
434
+ - **`field_mapping`** (at data source root): Maps Calpendo fields to worklist fields
435
+ - **`window_mode`** (optional): `rolling` (default) or `daily`
436
+ - **`daily_window`** (optional): `{"start_time": [h, m], "end_time": [h, m]}`
437
+ - Use **`_extract`** for regex-based field extraction:
438
+ - **`pattern`**: Regular expression pattern (use `\\` for escaping in JSON)
439
+ - **`group`**: Capture group number (0 = full match, 1+ = capture groups)
440
+
441
+ ### Regex Pattern Examples
442
+
443
+ Common patterns for extracting information from Calpendo booking titles:
444
+
445
+ ```json
446
+ {
447
+ "patient_id": {
448
+ "source_field": "title",
449
+ "_extract": {
450
+ "pattern": "^([A-Z0-9]+)_.*",
451
+ "group": 1
452
+ }
453
+ },
454
+ "patient_name": {
455
+ "source_field": "title",
456
+ "_extract": {
457
+ "pattern": "^[A-Z0-9]+_(.+)$",
458
+ "group": 1
459
+ }
460
+ },
461
+ "study_description": {
462
+ "source_field": "properties.project.formattedName",
463
+ "_extract": {
464
+ "pattern": "^([^(]+)",
465
+ "group": 1
466
+ }
467
+ }
468
+ }
469
+ ```
470
+
471
+ ### Troubleshooting
472
+
473
+ **Authentication Errors:**
474
+ - Verify environment variables are set correctly
475
+ - Check Calpendo username/password are valid
476
+ - Ensure API access is enabled for your account
477
+
478
+ **No Bookings Synced:**
479
+ - Check `resources` list matches actual Calpendo resource names
480
+ - Verify `status_filter` isn't too restrictive
481
+ - Check booking dates are within the rolling window (current time ± lookback window)
482
+
483
+ **Regex Extraction Failures:**
484
+ - Test regex patterns with sample data before deployment
485
+ - Check JSON escaping (use `\\` for backslashes)
486
+ - Set logging to DEBUG to see extraction warnings
487
+
488
+ ### Workflow Notes
489
+
490
+ - MPPS status updates are owned by N-CREATE/N-SET; sync operations do not overwrite existing `performed_procedure_step_status` values.
491
+
492
+ For more details, see the [Calpendo plugin quickstart](specs/002-calpendo-plugin/quickstart.md).
493
+
494
+ ### Legacy Configuration Format (Deprecated)
495
+
496
+ ⚠️ **The legacy configuration format is deprecated but still supported for backward compatibility.**
497
+
498
+ If you're using the old format, Pylantir will automatically convert it to the new format at runtime:
499
+
500
+ ```json
501
+ {
502
+ "db_path": "/path/to/worklist.db",
503
+ "db_echo": "False",
504
+ "db_update_interval": 60,
505
+ "operation_interval": {"start_time": [0,0], "end_time": [23,59]},
226
506
  "site": "792",
227
507
  "redcap2wl": {
228
508
  "study_id": "study_id",
229
- "instrument": "redcap_repeat_instrument",
230
- "session_id" : "mri_instance",
231
- "family_id": "family_id",
232
- "youth_dob_y": "youth_dob_y",
233
- "t1_date": "t1_date",
234
- "demo_sex": "demo_sex",
235
- "scheduled_date": "mri_date",
236
- "scheduled_time": "mri_time",
237
- "mri_wt_lbs": "patient_weight_lb",
238
- "referring_physician": "referring_physician_name",
239
- "performing_physician": "performing_physician",
240
- "station_name": "station_name",
241
- "status": "performed_procedure_step_status"
509
+ "demo_sex": "demo_sex"
242
510
  },
243
511
  "protocol": {
244
- "792": "BRAIN_MRI_3T",
245
- "mapping": "GEHC"
512
+ "792": "BRAIN_MRI_3T"
246
513
  }
247
514
  }
248
515
  ```
249
516
 
517
+ When using the legacy format, you'll see a deprecation warning:
518
+ ```
519
+ WARNING: Legacy configuration format detected.
520
+ Consider migrating to 'data_sources' format for better flexibility.
521
+ ```
522
+
523
+ **Migration Note**: To migrate from legacy to new format:
524
+ 1. Rename `redcap2wl` → `field_mapping`
525
+ 2. Move `site` → `config.site_id`
526
+ 3. Move `protocol[site]` → `config.protocol`
527
+ 4. Move `db_update_interval` → `sync_interval`
528
+ 5. Wrap everything in a `data_sources` array with `name`, `type`, and `enabled` fields
529
+
530
+ See `config/mwl_config_multi_source_example.json` for a complete example.
531
+
250
532
  ### Memory Management (Optional)
251
533
 
252
534
  When you install the `monitoring` optional dependency (`pip install pylantir[monitoring]`), Pylantir gains enhanced memory monitoring capabilities during REDCap synchronization:
@@ -0,0 +1,25 @@
1
+ pylantir/__init__.py,sha256=kl2Et644PvUIvziU4BTxiTD1W4_g7E0xBYCHgPE6RZc,363
2
+ pylantir/api_server.py,sha256=NFrme9T6DSe9EAbW7LMZgqYD1wDJIm9NLfH79sdXTjo,23369
3
+ pylantir/auth_db_setup.py,sha256=yfhF8Eo6AVSbqZcC6-W0SPPXC1mkL7Dp9b8UxkI4GVc,5911
4
+ pylantir/auth_models.py,sha256=v_xg5-YD4S7oafl2SDTC_ExmcasROWdVHG1tqn_qE0A,2707
5
+ pylantir/auth_utils.py,sha256=Gr6tBR_IZXY61xiadhsc7BpnCRYeFYkAtN5QJW_wE8Q,5761
6
+ pylantir/db_concurrency.py,sha256=4tCiHW8cxcrPxDEzXEBzyUviiQiO-7B2skxSaC40t9M,6387
7
+ pylantir/db_setup.py,sha256=C0AwZ3Pa-lE821SQ3DtLlAPb83def3y5AY8EBmmAHXM,3664
8
+ pylantir/models.py,sha256=qv1pQa0sWWG-wMECof3GsTgpnzltkWqYjK5UiKAoT0Y,1907
9
+ pylantir/mwl_server.py,sha256=GMJDcK0u_KM3oa6UqQ87NxMVye2pvG2cdkcI9k_iExg,10338
10
+ pylantir/populate_db.py,sha256=PL70ZmdHA401_wTO7tBrlqMsviGcoR9fensJsXel6Ew,2306
11
+ pylantir/redcap_to_db.py,sha256=buUl27-ACoCeuJkm8WadIb8Mta3CDCqrHGhNkRxLJBY,21437
12
+ pylantir/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ pylantir/cli/run.py,sha256=D_c6iKE273LpfRCvHfmfN-b3K0XjX-KpwWY5eV_PPdE,37435
14
+ pylantir/config/calpendo_config_example.json,sha256=F8DXfq2CR6Dmfj35nVH-q0duIpvHsv7Tw1cfhW5q56k,1942
15
+ pylantir/config/config_example_with_cors.json,sha256=4F6YCOYMIPOZVnEdrWw3txIPWUyA3hRBIRs-zS5h2Vk,2885
16
+ pylantir/config/mwl_config.json,sha256=hz7n3Ii9R9sFvrgPERlbQMu0rLP-bpN5sTvRYuRD74k,1636
17
+ pylantir/data_sources/__init__.py,sha256=g9ishvpYxbE8rQjJwHHoAaCRNDcwJ1w0SIYmn8WVvXs,2310
18
+ pylantir/data_sources/base.py,sha256=eOc2jo7RxYnkEdAttPHJ2o4LI3t9NdT22NXsFN9OEOg,3600
19
+ pylantir/data_sources/calpendo_plugin.py,sha256=tVPwFwK_38_tdgWjvh9LNmnjTaiygQqECD5jdjo0VVQ,27709
20
+ pylantir/data_sources/redcap_plugin.py,sha256=BEw85cz8DhF8VqZIENQ8ZDF5IB1lg1UYB6BqEIzwqbk,12816
21
+ pylantir-0.3.0.dist-info/entry_points.txt,sha256=vxaxvfGppLqRt9_4sqNDdP6b2jlgpcHIwP7UQfrM1T0,50
22
+ pylantir-0.3.0.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
23
+ pylantir-0.3.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
24
+ pylantir-0.3.0.dist-info/METADATA,sha256=TdWd9E24hLgcCGNOuTLAy5htOfTAPwJzWd2LvXX3YoI,28213
25
+ pylantir-0.3.0.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- pylantir/__init__.py,sha256=kl2Et644PvUIvziU4BTxiTD1W4_g7E0xBYCHgPE6RZc,363
2
- pylantir/api_server.py,sha256=PLhHv1fzDptg5ujP7MgvBC43bKyDmCIT-hxmM4yB5PI,23177
3
- pylantir/auth_db_setup.py,sha256=yfhF8Eo6AVSbqZcC6-W0SPPXC1mkL7Dp9b8UxkI4GVc,5911
4
- pylantir/auth_models.py,sha256=v_xg5-YD4S7oafl2SDTC_ExmcasROWdVHG1tqn_qE0A,2707
5
- pylantir/auth_utils.py,sha256=Gr6tBR_IZXY61xiadhsc7BpnCRYeFYkAtN5QJW_wE8Q,5761
6
- pylantir/db_concurrency.py,sha256=4tCiHW8cxcrPxDEzXEBzyUviiQiO-7B2skxSaC40t9M,6387
7
- pylantir/db_setup.py,sha256=ljL3u6RTj1W7JqAsi_iYvV0rRUtwRut66X4IDAMQmCQ,3572
8
- pylantir/models.py,sha256=bKgI0EN1VSYanPTOvEhEY2Zzqa0gDYLpVnE_KNQ6PEc,1780
9
- pylantir/mwl_server.py,sha256=GMJDcK0u_KM3oa6UqQ87NxMVye2pvG2cdkcI9k_iExg,10338
10
- pylantir/populate_db.py,sha256=KIbkVA-EAuTlDArXMFOHkjMmVfjlsTApj7S1wpUu1bM,2207
11
- pylantir/redcap_to_db.py,sha256=rzA9VZl2qG67Ff82lxKgpXFVVkrmxBlr7Fd5OZORrVU,19476
12
- pylantir/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- pylantir/cli/run.py,sha256=4JI9cRwoKYGG53DDP32ZBfXlZp_5hl0C3A7FiM3JyJw,21885
14
- pylantir/config/config_example_with_cors.json,sha256=4F6YCOYMIPOZVnEdrWw3txIPWUyA3hRBIRs-zS5h2Vk,2885
15
- pylantir/config/mwl_config.json,sha256=I1nPzXofmw2JviS7hEOw01ExdL6pGdgH46rcKYu6ofo,1437
16
- pylantir-0.2.3.dist-info/entry_points.txt,sha256=vxaxvfGppLqRt9_4sqNDdP6b2jlgpcHIwP7UQfrM1T0,50
17
- pylantir-0.2.3.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
18
- pylantir-0.2.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
19
- pylantir-0.2.3.dist-info/METADATA,sha256=_QLhbm0N61fQGwKtlZHPONSlchoJGCm1Dgh4yIi0nVU,19888
20
- pylantir-0.2.3.dist-info/RECORD,,