Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat:json.dumps,json.dump accuracy improvements#13960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
max-muoto wants to merge18 commits intopython:main
base:main
Choose a base branch
Loading
frommax-muoto:improve-json-module-typing

Conversation

max-muoto
Copy link
Contributor

@max-muotomax-muoto commentedMay 8, 2025
edited
Loading

This PR addresses#13781 by makingjson.dumps andjson.dump more accurate:

  • Whendefault isn't provided, only JSON serializable types are supported (as accurate we can get, we'll go through trade-offs)
  • Whendefault is provided, the type must match that of the first call argument fordefault or what we consider JSON-serializable .

Trade-offs:

  • For reasons described hereDefine a JSON type typing#182 (comment) less accurateSequence andMapping typing is needed to support nested types properly but this will obviously still be a big improvement overAny.
  • As discussedhere,TypedDicts are only compatible withMapping[str, object] would it would be far preferable to useMapping[str, _JSON] closing off typed dictionaries is going to lead to a noticeable number of false positives.
  • Type-checking custom encoders isn't practical. Realistically to do this we would need to introduce generics onJSONEncoder (defaulting to our custom JSON type as the default) however it would be impractical for users to supply said generic param considering it doesn't exist at runtime. As a result an overload exists to acceptobject in the case that any customJSONEncoder is provided.

@max-muotomax-muoto changed the titlefeat: Improvejson.dumps,json.dump typingfeat:json.dumps,json.dump accuracy improvementsMay 9, 2025
@max-muotomax-muoto marked this pull request as ready for reviewMay 9, 2025 00:24
@github-actionsGitHub Actions

This comment has been minimized.

@max-muoto
Copy link
ContributorAuthor

max-muoto commentedMay 9, 2025
edited
Loading

CC:@srittau if you're interested in reviewing.

@github-actionsGitHub Actions

This comment has been minimized.

@max-muotomax-muoto marked this pull request as draftMay 9, 2025 01:42
@github-actionsGitHub Actions

This comment has been minimized.

@max-muotomax-muotoforce-pushed theimprove-json-module-typing branch 2 times, most recently from3ca5208 toa05d94aCompareMay 9, 2025 02:13
@github-actionsGitHub Actions

This comment has been minimized.

@github-actionsGitHub Actions

This comment has been minimized.

@max-muotomax-muoto marked this pull request as ready for reviewMay 9, 2025 02:45
@max-muotomax-muoto marked this pull request as draftMay 9, 2025 02:54
@github-actionsGitHub Actions

This comment has been minimized.

@max-muotomax-muoto marked this pull request as ready for reviewMay 9, 2025 03:48
@github-actionsGitHub Actions
Copy link
Contributor

Diff frommypy_primer, showing the effect of this PR on open source code:

spark (https://github.com/apache/spark)+ python/pyspark/pandas/config.py:409: error: Argument 1 to "dumps" has incompatible type "Any | _NoValueType"; expected "_JSON"  [arg-type]pandas (https://github.com/pandas-dev/pandas)+ pandas/io/parquet.py:191: error: Argument 1 to "dumps" has incompatible type "dict[Hashable, Any]"; expected "_JSON"  [arg-type]pytest (https://github.com/pytest-dev/pytest)+ src/_pytest/cacheprovider.py:191: error: No overload variant of "dumps" matches argument types "object", "bool", "int"  [call-overload]+ src/_pytest/cacheprovider.py:191: note: Possible overload variants:+ src/_pytest/cacheprovider.py:191: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ src/_pytest/cacheprovider.py:191: note:     def [_T] dumps(obj: Union[_JSON, _T], *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ src/_pytest/cacheprovider.py:191: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: Optional[Callable[[Any], Any]] = ..., sort_keys: bool = ..., **kwds: Any) -> strspack (https://github.com/spack/spack)+ lib/spack/spack/util/spack_json.py:26: error: Unused "type: ignore" comment  [unused-ignore]+ lib/spack/spack/util/spack_json.py:26: error: No overload variant of "dumps" matches argument types "dict[Any, Any]", "dict[str, tuple[str, str] | None]"  [call-overload]+ lib/spack/spack/util/spack_json.py:26: note: Error code "call-overload" not covered by "type: ignore" comment+ lib/spack/spack/util/spack_json.py:26: note: Possible overload variants:+ lib/spack/spack/util/spack_json.py:26: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ lib/spack/spack/util/spack_json.py:26: note:     def [_T] dumps(obj: _JSON | _T, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ lib/spack/spack/util/spack_json.py:26: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ lib/spack/spack/util/spack_json.py:27: error: Unused "type: ignore" comment  [unused-ignore]+ lib/spack/spack/util/spack_json.py:27: error: No overload variant of "dump" matches argument types "dict[Any, Any]", "Any", "dict[str, tuple[str, str] | None]"  [call-overload]+ lib/spack/spack/util/spack_json.py:27: note: Error code "call-overload" not covered by "type: ignore" comment+ lib/spack/spack/util/spack_json.py:27: note: Possible overload variants:+ lib/spack/spack/util/spack_json.py:27: note:     def dump(obj: _JSON, fp: SupportsWrite[str], *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> None+ lib/spack/spack/util/spack_json.py:27: note:     def [_T] dump(obj: _JSON | _T, fp: SupportsWrite[str], *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder] | None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> None+ lib/spack/spack/util/spack_json.py:27: note:     def dump(obj: object, fp: SupportsWrite[str], *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> Nonestrawberry (https://github.com/strawberry-graphql/strawberry)+ strawberry/http/base.py:51: error: No overload variant of "dumps" matches argument type "object"  [call-overload]+ strawberry/http/base.py:51: note: Possible overload variants:+ strawberry/http/base.py:51: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ strawberry/http/base.py:51: note:     def [_T] dumps(obj: _JSON | _T, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ strawberry/http/base.py:51: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> strscrapy (https://github.com/scrapy/scrapy)+ scrapy/commands/settings.py:54: error: Argument 1 to "dumps" has incompatible type "dict[bool | float | int | str | None, Any]"; expected "_JSON"  [arg-type]cki-lib (https://gitlab.com/cki-project/cki-lib)+ cki_lib/owners.py:249: error: Argument "key" to "sorted" has incompatible type "Callable[[Mapping[str, object] | Sequence[_JSON] | float | bool | None], object | Any]"; expected "Callable[[Mapping[str, object] | Sequence[_JSON] | float | bool | None], SupportsDunderLT[Any] | SupportsDunderGT[Any]]"  [arg-type]+ cki_lib/owners.py:249: error: No overload variant of "__getitem__" of "Sequence" matches argument type "str"  [call-overload]+ cki_lib/owners.py:249: note: Possible overload variants:+ cki_lib/owners.py:249: note:     def __getitem__(self, int, /) -> _JSON+ cki_lib/owners.py:249: note:     def __getitem__(self, slice[Any, Any, Any], /) -> Sequence[_JSON]+ cki_lib/owners.py:249: error: Value of type "Mapping[str, object] | Sequence[_JSON] | float | bool | None" is not indexable  [index]+ cki_lib/owners.py:249: error: Incompatible return value type (got "object | Any", expected "SupportsDunderLT[Any] | SupportsDunderGT[Any]")  [return-value]poetry (https://github.com/python-poetry/poetry)+ src/poetry/utils/cache.py:181: error: No overload variant of "dumps" matches argument type "T"  [call-overload]+ src/poetry/utils/cache.py:181: note: Possible overload variants:+ src/poetry/utils/cache.py:181: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ src/poetry/utils/cache.py:181: note:     def [_T] dumps(obj: _JSON | _T, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ src/poetry/utils/cache.py:181: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ src/poetry/utils/cache.py:211: error: No overload variant of "dumps" matches argument types "object", "bool", "tuple[str, str]", "bool"  [call-overload]+ src/poetry/utils/cache.py:211: note: Possible overload variants:+ src/poetry/utils/cache.py:211: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ src/poetry/utils/cache.py:211: note:     def [_T] dumps(obj: _JSON | _T, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ src/poetry/utils/cache.py:211: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> strmypy (https://github.com/python/mypy)+ mypy/util.py:935: error: Returning Any from function declared to return "bytes"  [no-any-return]+ mypy/util.py:935: note: See https://mypy.rtfd.io/en/stable/_refs.html#code-no-any-return for more info+ mypy/util.py:935: error: No overload variant of "dumps" matches argument types "object", "int", "bool"  [call-overload]+ mypy/util.py:935: note: Possible overload variants:+ mypy/util.py:935: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ mypy/util.py:935: note:     def [_T] dumps(obj: Union[_JSON, _T], *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ mypy/util.py:935: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: Optional[Callable[[Any], Any]] = ..., sort_keys: bool = ..., **kwds: Any) -> str+ mypy/util.py:935: note: See https://mypy.rtfd.io/en/stable/_refs.html#code-call-overload for more info+ mypy/util.py:938: error: Returning Any from function declared to return "bytes"  [no-any-return]+ mypy/util.py:938: error: No overload variant of "dumps" matches argument types "object", "bool", "tuple[str, str]"  [call-overload]+ mypy/util.py:938: note: Possible overload variants:+ mypy/util.py:938: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ mypy/util.py:938: note:     def [_T] dumps(obj: Union[_JSON, _T], *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ mypy/util.py:938: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: Union[int, str, None] = ..., separators: Optional[tuple[str, str]] = ..., default: Optional[Callable[[Any], Any]] = ..., sort_keys: bool = ..., **kwds: Any) -> strzulip (https://github.com/zulip/zulip)+ zerver/lib/markdown/api_arguments_table_generator.py:170: error: No overload variant of "dumps" matches argument type "object"  [call-overload]+ zerver/lib/markdown/api_arguments_table_generator.py:170: note: Possible overload variants:+ zerver/lib/markdown/api_arguments_table_generator.py:170: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ zerver/lib/markdown/api_arguments_table_generator.py:170: note:     def [_T] dumps(obj: _JSON | _T, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ zerver/lib/markdown/api_arguments_table_generator.py:170: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ zerver/openapi/markdown_extension.py:243: error: No overload variant of "dumps" matches argument types "object", "bool"  [call-overload]+ zerver/openapi/markdown_extension.py:243: note: Possible overload variants:+ zerver/openapi/markdown_extension.py:243: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ zerver/openapi/markdown_extension.py:243: note:     def [_T] dumps(obj: _JSON | _T, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ zerver/openapi/markdown_extension.py:243: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ zerver/openapi/markdown_extension.py:258: error: No overload variant of "dumps" matches argument type "object"  [call-overload]+ zerver/openapi/markdown_extension.py:258: note: Possible overload variants:+ zerver/openapi/markdown_extension.py:258: note:     def dumps(obj: _JSON, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ zerver/openapi/markdown_extension.py:258: note:     def [_T] dumps(obj: _JSON | _T, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: None = ..., indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[_T], _JSON], sort_keys: bool = ..., **kwds: Any) -> str+ zerver/openapi/markdown_extension.py:258: note:     def dumps(obj: object, *, skipkeys: bool = ..., ensure_ascii: bool = ..., check_circular: bool = ..., allow_nan: bool = ..., cls: type[JSONEncoder], indent: int | str | None = ..., separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any) -> str+ zerver/openapi/markdown_extension.py:264: error: Incompatible return value type (got "object", expected "str")  [return-value]+ zerver/lib/bot_lib.py:47: error: Incompatible types in assignment (expression has type overloaded function, variable has type "Callable[[object], str]")  [assignment]

@JelleZijlstra
Copy link
Member

I don't think we can do this, it will lead to too many false positives.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants
@max-muoto@JelleZijlstra

[8]ページ先頭

©2009-2025 Movatter.jp