Skip to content

Optional parameters should accept None (e.g., pageToken: str | None) #71

@ryo-tagami

Description

@ryo-tagami

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: error

Expected

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:

  1. All API methods are generated by createMethod (except _next methods which don't take user parameters)

  2. 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) ...
  3. 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 occurrences
  • int = ...: ~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] = type

This change only affects required: false parameters, so type safety for required parameters is preserved.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions