phactor 0.3.2__tar.gz → 0.4.0__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 (26) hide show
  1. {phactor-0.3.2 → phactor-0.4.0}/CHANGELOG.md +22 -0
  2. {phactor-0.3.2 → phactor-0.4.0}/PKG-INFO +55 -1
  3. {phactor-0.3.2 → phactor-0.4.0}/README.md +54 -0
  4. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/__init__.py +12 -0
  5. phactor-0.4.0/src/phactor/_version.py +1 -0
  6. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/cohorts/client.py +5 -1
  7. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/cohorts/models.py +69 -0
  8. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/cohorts/query.py +8 -0
  9. phactor-0.3.2/src/phactor/_version.py +0 -1
  10. {phactor-0.3.2 → phactor-0.4.0}/.gitignore +0 -0
  11. {phactor-0.3.2 → phactor-0.4.0}/LICENSE +0 -0
  12. {phactor-0.3.2 → phactor-0.4.0}/pyproject.toml +0 -0
  13. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/_graphql.py +0 -0
  14. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/_http.py +0 -0
  15. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/auth.py +0 -0
  16. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/client.py +0 -0
  17. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/cohorts/__init__.py +0 -0
  18. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/cohorts/builder.py +0 -0
  19. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/config.py +0 -0
  20. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/exceptions.py +0 -0
  21. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/pandas.py +0 -0
  22. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/py.typed +0 -0
  23. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/sites/__init__.py +0 -0
  24. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/sites/client.py +0 -0
  25. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/sites/models.py +0 -0
  26. {phactor-0.3.2 → phactor-0.4.0}/src/phactor/sites/query.py +0 -0
@@ -6,6 +6,28 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
  While the SDK is pre-1.0 (`0.x`), breaking changes may accompany a minor version bump.
8
8
 
9
+ ## [0.4.0] - 2026-10-06
10
+
11
+ ### Added
12
+
13
+ - **Nearby provider sites.** A `PROXIMITY` grouping can set
14
+ `"includeNearbyProviderSites": True` (`GroupingInput.include_nearby_provider_sites`)
15
+ to also get your subscribed providers' sites inside each radius or distance
16
+ band. The result is `AnalyzeCohortsPayload.nearby_provider_sites`, `None`
17
+ when not requested.
18
+ - New models `NearbyProviderSites` (`status`, `truncated`, `sites`),
19
+ `NearbyProviderSite` (address, coordinates, `providers`, `matches`),
20
+ `NearbyProviderRef` (`id`, `name`, `provider_type`, `color`) and
21
+ `NearbyProviderSiteMatch` (`site_name`, coordinates, `distance_miles`).
22
+ - New enums `NearbyProviderSitesStatus` (`AVAILABLE`, `UNAVAILABLE`) and
23
+ `DataProviderType`. Like the 0.3.2 response enums, an unknown value from
24
+ the API is kept as a plain string.
25
+ - At most 500 sites are returned, nearest first; `truncated` is `True` when
26
+ more matched.
27
+ - With the option on, the server rejects the request (`GraphQLError`) when it
28
+ has more than 50 distinct providers, more than 25 grouping sites, or a radius
29
+ or distance band outside 1-250 miles. Without it these limits do not apply.
30
+
9
31
  ## [0.3.2] - 2026-09-24
10
32
 
11
33
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: phactor
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: Python SDK for the Phactor clinical trial feasibility platform
5
5
  Project-URL: Homepage, https://phactor.ai
6
6
  Project-URL: Documentation, https://docs.phactor.ai
@@ -282,3 +282,57 @@ There are three independent operator levels:
282
282
  Exclusion groups are always unioned and subtracted from the pathway's combined
283
283
  inclusion result. For example, an `OR` pathway with inclusion groups `A` and `B`
284
284
  and exclusion group `E` evaluates as `(A OR B) EXCEPT E`.
285
+
286
+ ## Geographic Grouping
287
+
288
+ Group cohort results by geography using PROXIMITY and RADIUS or DISTANCE_BANDS mode:
289
+
290
+ ```python
291
+ result = client.cohorts.analyze(
292
+ providers=[...],
293
+ cohort_groups=[...],
294
+ grouping={
295
+ "type": "PROXIMITY",
296
+ "proximityMode": "RADIUS",
297
+ "sites": [
298
+ {"name": "Johns Hopkins", "latitude": 39.2963, "longitude": -76.5927, "radiusMiles": 25}
299
+ ],
300
+ },
301
+ )
302
+ for analysis in result.analyses:
303
+ for group in analysis.site_radius_results or []:
304
+ print(group.site_name, group.count, group.percentage)
305
+ ```
306
+
307
+ ### Provider sites near each grouping site
308
+
309
+ ```python
310
+ from phactor import NearbyProviderSitesStatus
311
+
312
+ result = client.cohorts.analyze(
313
+ providers=[...],
314
+ cohort_groups=[...],
315
+ grouping={
316
+ "type": "PROXIMITY",
317
+ "proximityMode": "RADIUS",
318
+ "sites": [
319
+ {"name": "Johns Hopkins", "latitude": 39.2963, "longitude": -76.5927, "radiusMiles": 25}
320
+ ],
321
+ "includeNearbyProviderSites": True,
322
+ },
323
+ )
324
+ nearby = result.nearby_provider_sites
325
+ if nearby and nearby.status == NearbyProviderSitesStatus.AVAILABLE:
326
+ for site in nearby.sites:
327
+ print(site.name, [p.name for p in site.providers], [m.distance_miles for m in site.matches])
328
+ ```
329
+
330
+ Only sites of subscribed providers you included in `providers` are returned. Each provider
331
+ carries its `provider_type` (a `DataProviderType`) and its display `color` (`#rrggbb`).
332
+ `NearbyProviderSitesStatus.UNAVAILABLE` means the site lookup failed; the cohort counts are
333
+ still valid. At most the nearest 500 sites are returned; `truncated` is `True` when there were
334
+ more.
335
+
336
+ With `includeNearbyProviderSites` on, the request is rejected with a `GraphQLError` when it has
337
+ more than 50 distinct providers, more than 25 grouping sites, or a radius or distance band outside
338
+ 1-250 miles.
@@ -243,3 +243,57 @@ There are three independent operator levels:
243
243
  Exclusion groups are always unioned and subtracted from the pathway's combined
244
244
  inclusion result. For example, an `OR` pathway with inclusion groups `A` and `B`
245
245
  and exclusion group `E` evaluates as `(A OR B) EXCEPT E`.
246
+
247
+ ## Geographic Grouping
248
+
249
+ Group cohort results by geography using PROXIMITY and RADIUS or DISTANCE_BANDS mode:
250
+
251
+ ```python
252
+ result = client.cohorts.analyze(
253
+ providers=[...],
254
+ cohort_groups=[...],
255
+ grouping={
256
+ "type": "PROXIMITY",
257
+ "proximityMode": "RADIUS",
258
+ "sites": [
259
+ {"name": "Johns Hopkins", "latitude": 39.2963, "longitude": -76.5927, "radiusMiles": 25}
260
+ ],
261
+ },
262
+ )
263
+ for analysis in result.analyses:
264
+ for group in analysis.site_radius_results or []:
265
+ print(group.site_name, group.count, group.percentage)
266
+ ```
267
+
268
+ ### Provider sites near each grouping site
269
+
270
+ ```python
271
+ from phactor import NearbyProviderSitesStatus
272
+
273
+ result = client.cohorts.analyze(
274
+ providers=[...],
275
+ cohort_groups=[...],
276
+ grouping={
277
+ "type": "PROXIMITY",
278
+ "proximityMode": "RADIUS",
279
+ "sites": [
280
+ {"name": "Johns Hopkins", "latitude": 39.2963, "longitude": -76.5927, "radiusMiles": 25}
281
+ ],
282
+ "includeNearbyProviderSites": True,
283
+ },
284
+ )
285
+ nearby = result.nearby_provider_sites
286
+ if nearby and nearby.status == NearbyProviderSitesStatus.AVAILABLE:
287
+ for site in nearby.sites:
288
+ print(site.name, [p.name for p in site.providers], [m.distance_miles for m in site.matches])
289
+ ```
290
+
291
+ Only sites of subscribed providers you included in `providers` are returned. Each provider
292
+ carries its `provider_type` (a `DataProviderType`) and its display `color` (`#rrggbb`).
293
+ `NearbyProviderSitesStatus.UNAVAILABLE` means the site lookup failed; the cohort counts are
294
+ still valid. At most the nearest 500 sites are returned; `truncated` is `True` when there were
295
+ more.
296
+
297
+ With `includeNearbyProviderSites` on, the request is rejected with a `GraphQLError` when it has
298
+ more than 50 distinct providers, more than 25 grouping sites, or a radius or distance band outside
299
+ 1-250 miles.
@@ -30,6 +30,7 @@ from phactor.cohorts.models import (
30
30
  CriterionError,
31
31
  CriterionErrorDomain,
32
32
  CriterionErrorReason,
33
+ DataProviderType,
33
34
  DistanceBand,
34
35
  GenderValue,
35
36
  GeographicGroup,
@@ -48,6 +49,11 @@ from phactor.cohorts.models import (
48
49
  MedicationsInput,
49
50
  MedicationStatus,
50
51
  MedicationTypeEnum,
52
+ NearbyProviderRef,
53
+ NearbyProviderSite,
54
+ NearbyProviderSiteMatch,
55
+ NearbyProviderSites,
56
+ NearbyProviderSitesStatus,
51
57
  PdcFilterInput,
52
58
  ProcedureInput,
53
59
  ProcedureOutcome,
@@ -113,6 +119,8 @@ __all__ = [
113
119
  "CriterionErrorReason",
114
120
  "ResultGrouping",
115
121
  "ProximityMode",
122
+ "NearbyProviderSitesStatus",
123
+ "DataProviderType",
116
124
  # Input models
117
125
  "TimingInput",
118
126
  "AgeRangeInput",
@@ -148,6 +156,10 @@ __all__ = [
148
156
  "CriterionError",
149
157
  "DistanceBand",
150
158
  "GeographicGroup",
159
+ "NearbyProviderRef",
160
+ "NearbyProviderSite",
161
+ "NearbyProviderSiteMatch",
162
+ "NearbyProviderSites",
151
163
  "SiteDistanceBandResult",
152
164
  "SiteRadiusResult",
153
165
  # Site search
@@ -0,0 +1 @@
1
+ __version__ = "0.4.0"
@@ -156,7 +156,11 @@ class CohortsClient:
156
156
  age_buckets: Custom age range buckets for demographic breakdown.
157
157
  include_combined_demographic_breakdown:
158
158
  Include combined-population demographic breakdown.
159
- grouping: Geographic grouping configuration dict.
159
+ grouping: Geographic grouping configuration dict. With
160
+ ``includeNearbyProviderSites`` on, the server rejects the request
161
+ (``GraphQLError``) when it has more than 50 distinct providers,
162
+ more than 25 grouping sites, or a radius or distance band outside
163
+ 1-250 miles.
160
164
  global_filters: Optional global filters applied to all cohort groups
161
165
  (e.g. restrict the study to specific states or geographies).
162
166
  Returns:
@@ -608,6 +608,9 @@ class GroupingInput(BaseModel):
608
608
  # Opt-in exact radius / distance-band counts (PostGIS ST_DWithin
609
609
  # refine over the approximate H3 hex cover). Default None (approximate).
610
610
  exact: bool | None = None
611
+ # Opt-in: also return subscribed providers' sites inside each grouping radius
612
+ # (AnalyzeCohortsPayload.nearby_provider_sites). PROXIMITY only.
613
+ include_nearby_provider_sites: bool | None = None
611
614
 
612
615
 
613
616
  class GlobalFiltersInput(BaseModel):
@@ -773,9 +776,75 @@ class ProviderCohortAnalysis(BaseModel):
773
776
  site_distance_band_results: list[SiteDistanceBandResult] | None = None
774
777
 
775
778
 
779
+ class NearbyProviderSitesStatus(str, Enum):
780
+ """Whether the nearby provider site lookup succeeded. Values the server adds
781
+ later reach ``NearbyProviderSites.status`` as plain strings instead of failing."""
782
+
783
+ AVAILABLE = "AVAILABLE"
784
+ UNAVAILABLE = "UNAVAILABLE"
785
+
786
+
787
+ class DataProviderType(str, Enum):
788
+ """The kind of data a provider holds. Values the server adds later reach
789
+ ``NearbyProviderRef.provider_type`` as plain strings instead of failing."""
790
+
791
+ PHARMACY = "PHARMACY"
792
+ HOSPITAL = "HOSPITAL"
793
+ LABORATORY = "LABORATORY"
794
+ EHR_SYSTEM = "EHR_SYSTEM"
795
+ CLAIMS = "CLAIMS"
796
+ GENOMICS = "GENOMICS"
797
+ OTHER = "OTHER"
798
+
799
+
800
+ class NearbyProviderRef(BaseModel):
801
+ model_config = _MODEL_CONFIG
802
+
803
+ id: str
804
+ name: str
805
+ # A value this SDK version does not know yet stays a plain string.
806
+ provider_type: DataProviderType | str = Field(union_mode="left_to_right")
807
+ # The provider's display color as a ``#rrggbb`` hex string.
808
+ color: str
809
+
810
+
811
+ class NearbyProviderSiteMatch(BaseModel):
812
+ model_config = _MODEL_CONFIG
813
+
814
+ site_name: str
815
+ latitude: float
816
+ longitude: float
817
+ distance_miles: float
818
+
819
+
820
+ class NearbyProviderSite(BaseModel):
821
+ model_config = _MODEL_CONFIG
822
+
823
+ id: str
824
+ name: str
825
+ address: str | None = None
826
+ city: str | None = None
827
+ state: str | None = None
828
+ postal_code: str | None = None
829
+ latitude: float
830
+ longitude: float
831
+ providers: list[NearbyProviderRef]
832
+ matches: list[NearbyProviderSiteMatch]
833
+
834
+
835
+ class NearbyProviderSites(BaseModel):
836
+ model_config = _MODEL_CONFIG
837
+
838
+ # A value this SDK version does not know yet stays a plain string.
839
+ status: NearbyProviderSitesStatus | str = Field(union_mode="left_to_right")
840
+ truncated: bool
841
+ sites: list[NearbyProviderSite]
842
+
843
+
776
844
  class AnalyzeCohortsPayload(BaseModel):
777
845
  model_config = _MODEL_CONFIG
778
846
 
779
847
  id: str
780
848
  analyses: list[ProviderCohortAnalysis]
781
849
  warnings: list[AnalysisWarning] | None = None
850
+ nearby_provider_sites: NearbyProviderSites | None = None
@@ -93,6 +93,14 @@ query AnalyzeCohorts($input: AnalyzeCohortsInput!) {
93
93
  code
94
94
  message
95
95
  }
96
+ nearbyProviderSites {
97
+ status truncated
98
+ sites {
99
+ id name address city state postalCode latitude longitude
100
+ providers { id name providerType color }
101
+ matches { siteName latitude longitude distanceMiles }
102
+ }
103
+ }
96
104
  }
97
105
  }
98
106
  """
@@ -1 +0,0 @@
1
- __version__ = "0.3.2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes