Skip to content

JSONType uses invariant Dict/List - causes type errors for compatible value types #65

@alex-raw

Description

@alex-raw

SDK version: couchbase 4.5.0
Python: 3.13
pyright: 1.1.408

I'm using the SDK with pyright and ran into a type error when passing query parameters with a typed JSON value type. I was surprised because the values I'm passing (str, int, etc.) should be semantically compatible with JSONType.

Repro:

from couchbase.options import QueryOptions

type JSONValue = str | int | float | bool | None

params: dict[str, JSONValue] = {"name": "test", "count": 42}
QueryOptions(named_parameters=params)
/tmp/repro.py:6:31 - error: Argument of type "dict[str, JSONValue]" cannot be assigned
  to parameter "named_parameters" of type "Dict[str, JSONType] | None" in function "__init__"
    Type "dict[str, JSONValue]" is not assignable to type "Dict[str, JSONType] | None"
      "dict[str, JSONValue]" is not assignable to "Dict[str, JSONType]"
        Type parameter "_VT@dict" is invariant, but "JSONValue" is not the same as "JSONType"
        Consider switching from "dict" to "Mapping" which is covariant in the value type
      "dict[str, JSONValue]" is not assignable to "None" (reportArgumentType)

The root cause is JSONType in _utils.py using Dict/List, which are invariant in their type parameters. Since the SDK only reads these values, named parameters via .items() + serialize, positional parameters via iteration, neither the dicts nor the lists are ever mutated. I think even a tuple currently works at runtime for positional parameters, but the current List annotation rejects it. Mapping/Sequence would work here. They're covariant in the value type, which is the standard choice for read-only parameters per PEP 484.

# _utils.py -- current
JSONType = Union[str, int, float, bool, None, Dict[str, Any], List[Any]]

# with covariant containers
JSONType = Union[str, int, float, bool, None, Mapping[str, Any], Sequence[Any]]

Happy to open a PR if this makes sense to you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions