-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Problem
Optional parameters (required: false in Discovery Documents) are typed as str = ... (or int = ..., etc.), but google-api-python-client accepts None for these parameters at runtime.
Example
Current stub:
def list(
self,
*,
pageSize: int = ...,
pageToken: str = ...,
**kwargs: typing.Any,
) -> ListAccessProposalsResponseHttpRequest: ...Actual usage that works at runtime but fails type checking:
token = get_token_from_cache() # may return None
service.files().list(pageToken=token) # Runtime: OK, mypy: errorExpected
def list(
self,
*,
pageSize: int | None = ...,
pageToken: str | None = ...,
**kwargs: typing.Any,
) -> ListAccessProposalsResponseHttpRequest: ...Root Cause
Discovery Documents define optional parameters as:
{
"pageToken": {
"type": "string",
"required": false
}
}create_stubs.py converts "type": "string" to str and marks non-required parameters with = ..., but does not add | None to the type.
Safety Verification
I verified that this change is safe by examining google-api-python-client's implementation:
-
All API methods are generated by
createMethod(except_nextmethods which don't take user parameters) -
None removal is unconditionally executed in every method call:
def method(self, **kwargs): # ... credential validation ... # ... unexpected argument check ... # None removal (always executed, no skip conditions) keys = list(kwargs.keys()) for name in keys: if kwargs[name] is None: del kwargs[name] # ... required parameter check (after None removal) ...
-
Behavior by parameter type:
required: true+None→ removed →TypeError: Missing required parameter(correctly rejected)required: false+None→ removed → works normally (parameter omitted from request)
Impact
This affects a large number of parameters:
str = ...: ~16,800 occurrencesint = ...: ~5,000 occurrences
Suggested Fix
In create_stubs.py, add | None for non-required parameters:
# Around line 213-217
type = get_type(parameter)
if parameter.get("repeated"):
assert "_list[" not in type and type != "_list"
type = f"{type} | _list[{type}]"
if not parameter.get("required"): # Add this
type = f"{type} | None"
parameters[parameter_name] = typeThis change only affects required: false parameters, so type safety for required parameters is preserved.