`_api_encode` encodes bool/datetime list elements raw (e.g. `flags[0]=True` instead of `true`)

Open Beginner friendly
#1,956 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 6 days

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
api, backend

Research direction

Read stripe/_encode.py and trace how _api_encode handles direct list elements compared with top-level values. Add regression tests for boolean and datetime list elements, then run the relevant encoding tests; done means both serialize to the expected lowercase booleans and Unix timestamps. The issue author says a fix is prepared, but no pull request is linked and the issue has no comments.

Written by the indexing model from the issue text.

Description

bug
Describe the bug

stripe._encode._api_encode converts bool and datetime values to the forms the API expects at the top level and inside nested dicts (bool → "true"/"false", datetime → unix timestamp), but yields them raw when they are direct elements of a list.

The request body/query string is built with urlencode(list(_api_encode(params))) (in _api_requestor.py), so a list parameter containing a boolean is serialized as "True"/"False" (Python str(bool)) and a list containing a datetime is serialized as its str() repr instead of a unix timestamp. Multipart form encoding is affected too, since MultipartDataGenerator.add_params also goes through _api_encode.

To Reproduce
import datetime
from urllib.parse import urlencode
from stripe._encode import _api_encode

dt = datetime.datetime(2024, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)

print(urlencode(list(_api_encode({"active": True}))))          # correct
print(urlencode(list(_api_encode({"flags": [True, False]}))))  # wrong
print(urlencode(list(_api_encode({"created": dt}))))           # correct
print(urlencode(list(_api_encode({"created": [dt]}))))         # wrong

Output:

active=true
flags%5B0%5D=True&flags%5B1%5D=False
created=1704164645
created%5B0%5D=2024-01-02+03%3A04%3A05%2B00%3A00

The top-level bool/datetime are encoded correctly (active=true, created=1704164645); the same values inside a list are not.

Expected behavior

A bool or datetime inside a list should be encoded the same way as at the top level:

  • flags[0]=true&flags[1]=false
  • created[0]=1704164645
Code snippets

OS

Any (reproduced on Linux)

Language version

Python 3.12 (version-independent)

Library version

main (89e8528)

API version

N/A — client-side request encoding, independent of API version

Additional context
Root cause

In _api_encode (stripe/_encode.py), the list branch handles dict/_data elements and nested list/tuple elements, but every other element — including bool and datetime.datetime — falls through to else: yield (encoded_key, sv) raw. The top-level code has explicit datetime and bool branches; the list branch does not.

(Nested dict values are unaffected because they recurse back through _api_encode; nested lists are unaffected because they go through _encode_nested_dict + recursion. Only direct scalar elements of a list are affected.)

Proposed fix

Mirror the top-level handling in the list branch:

elif isinstance(sv, datetime.datetime):
    yield (encoded_key, _encode_datetime(sv))
elif isinstance(sv, bool):
    yield (encoded_key, str(sv).lower())
else:
    yield (encoded_key, sv)

I've prepared this fix with regression tests on a branch: https://github.com/alphasafal/stripe-python/tree/fix/encode-list-bool-datetime — happy to open a PR if a maintainer would like one (the repo currently limits PR creation to collaborators).

Dominant language
Python
Stars
2.1k
Forks
547
Avg merge
5d 6h
Merged PRs (30d)
9

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from stripe/stripe-python

All issues in stripe/stripe-python

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.