Skip to content

Commit 218000a

Browse files
authored
Merge pull request #102 from ParclLabs/zach/dat-121-limit-total-cap-truncation-warning
fix(DAT-121): make property_v2 `limit` a total cap and warn on silent truncation
2 parents 006f51d + e9180a0 commit 218000a

7 files changed

Lines changed: 656 additions & 90 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
### v1.18.0
2+
- **`property_v2.search.retrieve`: `limit` is now a cap on the total number of properties returned, not a page size.** Pagination is handled internally to satisfy it. Previously, passing *any* explicit `limit` silently disabled auto-pagination, so `limit=1000` returned one page of 1,000 and discarded every remaining match with no error or warning. Calls with `limit <= 50000` are unaffected — same request, same results.
3+
- **`limit` above 50,000 now paginates instead of failing.** Previously the request was rejected by the API with `422 limit input should be less than or equal to 50000`.
4+
- **Partial results now warn instead of passing silently.** When `limit` withholds matching data, a `ParclLabsTruncationWarning` reports how many properties were returned versus how many matched (emitted once per session). Note credits are charged per *property* returned, not per event, and because the returned DataFrame is event-level, `len(df)` is not bounded by `limit`.
5+
- **Failed pages during pagination are now retried and reported.** Pages are retried up to 3 times with exponential backoff; if any still fail the result is returned with a `ParclLabsIncompleteResultWarning` and the failed offsets are listed in `metadata["incomplete_pages"]`. Previously a failed page was printed and skipped, returning short data indistinguishable from complete data.
6+
- Added a pagination integrity check that warns if the assembled pages do not yield the expected number of distinct properties.
7+
- New warning categories in `parcllabs.warnings` (`ParclLabsWarning`, `ParclLabsTruncationWarning`, `ParclLabsIncompleteResultWarning`) so callers can silence or escalate these via standard `warnings` filters.
8+
- Fixed an internal `auto_paginate` flag leaking into the request query string.
9+
- Fixed `_get_metadata` mutating the caller's raw first-page response via a shallow copy.
10+
111
### v1.17.2
212
- Added configurable request timeout to `ParclLabsClient`. Defaults to 10s connect / 90s read. Customizable via the `timeout` parameter on client instantiation.
313

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,46 @@ Gets a list of unique properties and their associated metadata and events based
480480

481481
**NOTE:** Use the `limit` parameter to specify the number of matched properties to return. If `limit` is not provided, all matched properties will be returned. Conceptually, you should set the `limit` to retrieve a sample of properties, and then if you want to retrieve all properties, make the same request again without the `limit` parameter.
482482

483+
`limit` is a cap on the total number of **properties** returned, and pagination is handled for you — values larger than the API's 50,000 per-request maximum are fetched across multiple pages rather than rejected. Two things to keep in mind:
484+
485+
- **Credits are charged per property returned, not per event.**
486+
- The returned DataFrame is event-level, so `len(df)` is *not* bounded by `limit` — a single property can contribute many rows.
487+
488+
If `limit` caps the result below the number of matching properties, a `ParclLabsTruncationWarning` is emitted (once per session) and both counts are available in the returned metadata. If any page fails after retries, the data is still returned but a `ParclLabsIncompleteResultWarning` is raised and the failed offsets are listed in `metadata["incomplete_pages"]`.
489+
490+
Both conditions are worth checking programmatically, especially in a loop over many markets where a warning is easy to miss:
491+
492+
```python
493+
results, metadata = client.property_v2.search.retrieve(parcl_ids=[2900187], limit=5)
494+
495+
counts = metadata["results"]
496+
if counts["returned_count"] < counts["total_available"]:
497+
print(
498+
f"Truncated: got {counts['returned_count']:,} of "
499+
f"{counts['total_available']:,} properties. Raise `limit`, or omit it entirely."
500+
)
501+
502+
if metadata.get("incomplete_pages"):
503+
print(f"Incomplete: pages failed at offsets {metadata['incomplete_pages']}")
504+
```
505+
506+
If a short result should be fatal for your pipeline, make those checks `assert`s or raise your own exception — treat a non-empty `incomplete_pages` as an incomplete dataset either way. Both warning types live in `parcllabs.warnings` and can be silenced or escalated with standard `warnings` filters:
507+
508+
```python
509+
import warnings
510+
511+
from parcllabs.warnings import ParclLabsIncompleteResultWarning, ParclLabsTruncationWarning
512+
513+
with warnings.catch_warnings():
514+
# Intentionally sampling? Silence the truncation notice.
515+
warnings.filterwarnings("ignore", category=ParclLabsTruncationWarning)
516+
517+
# Never accept a partial page silently -- make it raise instead.
518+
warnings.filterwarnings("error", category=ParclLabsIncompleteResultWarning)
519+
520+
results, metadata = client.property_v2.search.retrieve(parcl_ids=[2900187], limit=5)
521+
```
522+
483523

484524
Example request, note that only one of `parcl_ids`, `parcl_property_ids`, or `geo_coordinates` can be provided per request:
485525

parcllabs/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = "1.17.2"
1+
VERSION = "1.18.0"

parcllabs/schemas/schemas.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,21 @@ class PropertyV2RetrieveParams(BaseModel):
142142
)
143143

144144
# Pagination
145+
#
146+
# No upper bound: `limit` is a cap on the total number of properties returned,
147+
# and values above the API's per-request ceiling
148+
# (RequestLimits.PROPERTY_V2_MAX) are satisfied by paginating rather than
149+
# rejected. Omit to retrieve every matching property.
145150
limit: int | None = Field(
146151
default=None,
147152
ge=1,
148-
le=RequestLimits.PROPERTY_V2_MAX.value,
149-
description=f"Number of results to return (max: {RequestLimits.PROPERTY_V2_MAX.value})",
153+
description=(
154+
"Maximum number of properties to return in total. Values above "
155+
f"{RequestLimits.PROPERTY_V2_MAX.value} are fetched across multiple pages. "
156+
"Omit to retrieve all matching properties. Credits are charged per property "
157+
"returned; the returned DataFrame is event-level, so len(df) is not bounded "
158+
"by this value."
159+
),
150160
)
151161

152162
# Additional parameters

0 commit comments

Comments
 (0)