Skip to content

fix(helpers): keep a pagination zero in as_page - #113

Closed
CaptainAni187 wants to merge 1 commit into
smallest-inc:mainfrom
CaptainAni187:fix_as_page_drops_zero_pagination
Closed

CaptainAni187 wants to merge 1 commit into
smallest-inc:mainfrom
CaptainAni187:fix_as_page_drops_zero_pagination

Conversation

@CaptainAni187

@CaptainAni187 CaptainAni187 commented Sep 12, 2026

Copy link
Copy Markdown

as_page picks the pagination fields out of whichever key the endpoint used, and the candidates are chained with or:

total_count=(
    _get(data, "total_count")
    or _get(data, "total")
    ...
),
total_pages=_get(data, "total_pages") or _get(pagination, "total_pages"),

or skips a falsy value, and 0 is a perfectly real answer here. A page the server honestly reports as empty loses its zeros:

>>> from smallestai.atoms.helpers._envelope import as_page
>>> as_page({"data": {"agents": [], "total_count": 0, "total_pages": 0, "has_more": False}})
Page(items=[], total_count=None, total_pages=None, has_more=False)

total_count=None means "the server did not tell us", so a caller that pages until it has seen total_count items, or that renders "0 of N", cannot tell an empty result from a missing field.

It is also inconsistent depending on where the zero sits in the chain, because the last term of an or is returned whether or not it is truthy:

>>> as_page({"data": {"agents": [], "pagination": {"total": 0, "total_pages": 0, "has_more": False}}})
Page(items=[], total_count=None, total_pages=0, has_more=False)

Same payload, same kind of zero, one survives and one does not.

has_more is already correct, and it is the line directly underneath:

has_more=(
    _get(data, "has_more") if _get(data, "has_more") is not None else _get(pagination, "has_more")
),

That explicit is not None is there because False would hit the same trap. The numeric fields just never got the same treatment.

The change

A small _first_present helper that returns the first candidate which is not None, used for all three fields. Precedence is unchanged, so a flat field still wins over the nested pagination object whether or not it happens to be truthy. has_more moves onto the helper too, which is the same behaviour it had, just no longer spelled out inline.

Tests

Three added to tests/custom/test_as_page_envelope.py: the flat zeros, the nested zeros, and one pinning that a flat 0 still beats a nested 7 so the fix cannot quietly reorder precedence. All three fail on main. The existing seven are untouched and still pass.

_envelope.py is .fernignored, so a regen keeps this.

The total_count and total_pages candidates were chained with `or`, so a real 0
was skipped for the next candidate and an honestly empty page came back with
total_count None, which reads as "the server did not say". Pick the first
candidate that is not None instead, which is what the has_more line beside it
already did.
@crim-app

crim-app Bot commented Sep 12, 2026

Copy link
Copy Markdown

crim doesn't review pull requests automatically here.

Comment crim review on this pull request whenever you want a review.

@CaptainAni187

Copy link
Copy Markdown
Author

crim review

@crim-app

crim-app Bot commented Sep 12, 2026

Copy link
Copy Markdown

crim is reviewing this pull request. Findings will be posted shortly.

@crim-app

crim-app Bot commented Sep 12, 2026

Copy link
Copy Markdown

Good to merge

The bug where an honestly empty page pretended it had no idea how empty it was is now fixed, and _first_present finally teaches this code the difference between "zero" and "nothing." Ship it.

@crim-app crim-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

One-sentence assessment: A correct and well-scoped fix that stops as_page from discarding legitimate zero/false pagination values.

What this PR does

Replaces the a or b or ... truthiness chains in as_page with a _first_present helper that selects the first non-None value, so a server that honestly reports total_count: 0, total_pages: 0, or has_more: false no longer has those collapsed to None. The has_more rewrite is behaviorally equivalent to the prior is not None ternary, and precedence (flat fields before nested pagination) is preserved. Tests cover empty-page zeros, nested-pagination zeros, and flat-over-nested precedence.

Findings

No issues found.

@abhishekmishragithub

Copy link
Copy Markdown
Collaborator

Superseded by #120 (re-homed onto an upstream branch so CI could run; your commit is included with authorship preserved, and the test type-check gaps for #112/#118 were fixed there). Shipping in 5.12.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants