-
Notifications
You must be signed in to change notification settings - Fork 15
Type annotations for canonicaljson #49
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,5 +3,6 @@ include *.py | |
| include *.md | ||
| include LICENSE | ||
| include tox.ini | ||
| include pyproject.toml | ||
| prune .travis | ||
| prune debian | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -16,9 +16,14 @@ | |||||
| # limitations under the License. | ||||||
|
|
||||||
| import platform | ||||||
| from typing import Optional, Type | ||||||
| from typing import Any, Generator, Optional, Type | ||||||
|
|
||||||
| frozendict_type: Optional[Type] | ||||||
| try: | ||||||
| from typing import Protocol | ||||||
| except ImportError: # pragma: no cover | ||||||
| from typing_extensions import Protocol # type: ignore[misc] | ||||||
|
|
||||||
| frozendict_type: Optional[Type[Any]] | ||||||
| try: | ||||||
| from frozendict import frozendict as frozendict_type | ||||||
| except ImportError: | ||||||
|
|
@@ -27,22 +32,37 @@ | |||||
| __version__ = "1.6.0" | ||||||
|
|
||||||
|
|
||||||
| def _default(obj): # pragma: no cover | ||||||
| def _default(obj: object) -> object: # pragma: no cover | ||||||
| if type(obj) is frozendict_type: | ||||||
| # If frozendict is available and used, cast `obj` into a dict | ||||||
| return dict(obj) | ||||||
| return dict(obj) # type: ignore[call-overload] | ||||||
| raise TypeError( | ||||||
| "Object of type %s is not JSON serializable" % obj.__class__.__name__ | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| class Encoder(Protocol): # pragma: no cover | ||||||
| def encode(self, data: object) -> str: | ||||||
| pass | ||||||
|
|
||||||
| def iterencode(self, data: object) -> Generator[str, None, None]: | ||||||
| pass | ||||||
|
|
||||||
| def __call__(self, *args: Any, **kwargs: Any) -> "Encoder": | ||||||
| pass | ||||||
|
|
||||||
|
|
||||||
| class JsonLibrary(Protocol): | ||||||
| JSONEncoder: Encoder | ||||||
|
|
||||||
|
|
||||||
| # Declare these in the module scope, but they get configured in | ||||||
| # set_json_library. | ||||||
| _canonical_encoder = None | ||||||
| _pretty_encoder = None | ||||||
| _canonical_encoder: Encoder = None # type: ignore[assignment] | ||||||
| _pretty_encoder: Encoder = None # type: ignore[assignment] | ||||||
|
|
||||||
|
|
||||||
| def set_json_library(json_lib): | ||||||
| def set_json_library(json_lib: JsonLibrary) -> None: | ||||||
| """ | ||||||
| Set the underlying JSON library that canonicaljson uses to json_lib. | ||||||
|
|
||||||
|
|
@@ -69,7 +89,7 @@ def set_json_library(json_lib): | |||||
| ) | ||||||
|
|
||||||
|
|
||||||
| def encode_canonical_json(json_object): | ||||||
| def encode_canonical_json(json_object: object) -> bytes: | ||||||
| """Encodes the shortest UTF-8 JSON encoding with dictionary keys | ||||||
| lexicographically sorted by unicode code point. | ||||||
|
|
||||||
|
|
@@ -82,7 +102,7 @@ def encode_canonical_json(json_object): | |||||
| return s.encode("utf-8") | ||||||
|
|
||||||
|
|
||||||
| def iterencode_canonical_json(json_object): | ||||||
| def iterencode_canonical_json(json_object: object) -> Generator[bytes, None, None]: | ||||||
| """Encodes the shortest UTF-8 JSON encoding with dictionary keys | ||||||
| lexicographically sorted by unicode code point. | ||||||
|
|
||||||
|
|
@@ -95,7 +115,7 @@ def iterencode_canonical_json(json_object): | |||||
| yield chunk.encode("utf-8") | ||||||
|
|
||||||
|
|
||||||
| def encode_pretty_printed_json(json_object): | ||||||
| def encode_pretty_printed_json(json_object: object) -> bytes: | ||||||
|
||||||
| for c, expected in escaped.items(): | |
| self.assertEqual(encode_canonical_json(chr(c)), expected) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in ba77219.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arg, I wish we could figure out a way to kill this, but I don't think we can due to old Synapse versions which unconditionally install it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, I hadn't realised that Synapse imports and uses set_json_library.
IMO the dependencies that we control (canonicaljson, signedjson, matrix-common?) should be specified in Synapse's metadata with semver bounds to avoid this sort of thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO the dependencies that we control (canonicaljson, signedjson, matrix-common?) should be specified in Synapse's metadata with semver bounds to avoid this sort of thing.
Absolutely, but we didn't set an upper bound previously and there isn't really a way to go back and fix that (unless maybe once the Python's from those versions are unsupported?) 🤷
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| [tool.mypy] | ||
| show_error_codes = true | ||
| strict = true | ||
|
|
||
| files = ["."] | ||
| exclude = "setup.py" | ||
| #mypy_path = "stubs" | ||
|
|
||
| #[[tool.mypy.overrides]] | ||
|
||
| #module = [ | ||
| # "idna", | ||
| # "netaddr", | ||
| # "prometheus_client", | ||
| # "signedjson.*", | ||
| # "sortedcontainers", | ||
| #] | ||
| #ignore_missing_imports = true | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you do something silly like
import json as _jsonand then set these types to_json.JSONEncoder?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe---but that might cause further pain having to wrangle with
simplejson.(I was trying to avoid touching any of the import stuff---feels a bit icky.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Being completely honest a lot of this is overkill: the main benefit to Synapse is the existence of
-> bytesand-> Generator[bytes, None, None]return types.