{"id":13800111,"url":"https://github.com/davidfstr/trycast","last_synced_at":"2025-04-09T12:08:57.402Z","repository":{"id":40641203,"uuid":"316388611","full_name":"davidfstr/trycast","owner":"davidfstr","description":"trycast parses JSON-like values whose shape is defined by TypedDicts and other standard Python type hints.","archived":false,"fork":false,"pushed_at":"2024-08-03T13:49:43.000Z","size":889,"stargazers_count":80,"open_issues_count":6,"forks_count":6,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-01T17:18:56.767Z","etag":null,"topics":["parsing","python","runtime-typechecking","typechecker","typechecking","typing","validation"],"latest_commit_sha":null,"homepage":"https://dafoster.net/projects/trycast/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/davidfstr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-27T03:14:30.000Z","updated_at":"2025-01-21T22:11:56.000Z","dependencies_parsed_at":"2023-12-23T17:02:35.324Z","dependency_job_id":"95e41155-3dcb-461e-91b5-bed0f1706d98","html_url":"https://github.com/davidfstr/trycast","commit_stats":{"total_commits":181,"total_committers":5,"mean_commits":36.2,"dds":0.06077348066298338,"last_synced_commit":"cf658fbaab1bf937cf607de3c20085178ecb11c9"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidfstr%2Ftrycast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidfstr%2Ftrycast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidfstr%2Ftrycast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidfstr%2Ftrycast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davidfstr","download_url":"https://codeload.github.com/davidfstr/trycast/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036067,"owners_count":21037092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["parsing","python","runtime-typechecking","typechecker","typechecking","typing","validation"],"created_at":"2024-08-04T00:01:09.424Z","updated_at":"2025-04-09T12:08:57.379Z","avatar_url":"https://github.com/davidfstr.png","language":"Python","readme":"# trycast\n\n\u003cimg src=\"https://raw.githubusercontent.com/davidfstr/trycast/main/README/trycast-logo.svg\" title=\"trycast logo\" align=\"right\" /\u003e\n\nTrycast helps parses JSON-like values whose shape is defined by\n[typed dictionaries](https://www.python.org/dev/peps/pep-0589/#abstract)\n(TypedDicts) and other standard Python type hints.\n\nYou can use the `trycast()`, `checkcast()`, or `isassignable()` functions below\nfor parsing:\n\n\n### trycast()\n\nHere is an example of parsing a `Point2D` object defined as a `TypedDict`\nusing `trycast()`:\n\n```python\nfrom bottle import HTTPResponse, request, route  # Bottle is a web framework\nfrom trycast import trycast\nfrom typing import TypedDict\n\nclass Point2D(TypedDict):\n    x: float\n    y: float\n    name: str\n\n@route('/draw_point')\ndef draw_point_endpoint() -\u003e HTTPResponse:\n    request_json = request.json  # type: object\n    if (point := trycast(Point2D, request_json)) is None:\n        return HTTPResponse(status=400)  # Bad Request\n    draw_point(point)  # type is narrowed to Point2D\n    return HTTPResponse(status=200)\n\ndef draw_point(point: Point2D) -\u003e None:\n    ...\n```\n\nIn this example the `trycast` function is asked to parse a `request_json`\ninto a `Point2D` object, returning the original object (with its type narrowed\nappropriately) if parsing was successful.\n\nMore complex types can be parsed as well, such as the `Shape` in the following\nexample, which is a tagged union that can be either a `Circle` or `Rect` value:\n\n```python\nfrom bottle import HTTPResponse, request, route\nfrom trycast import trycast\nfrom typing import Literal, TypedDict\n\nclass Point2D(TypedDict):\n    x: float\n    y: float\n\nclass Circle(TypedDict):\n    type: Literal['circle']\n    center: Point2D  # a nested TypedDict!\n    radius: float\n\nclass Rect(TypedDict):\n    type: Literal['rect']\n    x: float\n    y: float\n    width: float\n    height: float\n\nShape = Circle | Rect  # a Tagged Union!\n\n@route('/draw_shape')\ndef draw_shape_endpoint() -\u003e HTTPResponse:\n    request_json = request.json  # type: object\n    if (shape := trycast(Shape, request_json)) is None:\n        return HTTPResponse(status=400)  # Bad Request\n    draw_shape(shape)  # type is narrowed to Shape\n    return HTTPResponse(status=200)  # OK\n```\n\n\u003e **Important:** Current limitations in the mypy typechecker require that you\n\u003e add an extra `cast(Optional[Shape], ...)` around the call to `trycast`\n\u003e in the example so that it is accepted by the typechecker without complaining:\n\u003e \n\u003e ```python\n\u003e shape = cast(Optional[Shape], trycast(Shape, request_json))\n\u003e if shape is None:\n\u003e     ...\n\u003e ```\n\u003e \n\u003e These limitations are in the process of being resolved by\n\u003e [introducing TypeForm support to mypy](https://github.com/python/mypy/issues/9773).\n\n### checkcast()\n\n`checkcast()` is similar to `trycast()` but instead of returning `None` \nwhen parsing fails it raises an exception explaining why and where the \nparsing failed.\n\nHere is an example of parsing a `Circle` object using `checkcast()`:\n\n```python\n\u003e\u003e\u003e from typing import Literal, TypedDict\n\u003e\u003e\u003e from trycast import checkcast\n\u003e\u003e\u003e \n\u003e\u003e\u003e class Point2D(TypedDict):\n...     x: float\n...     y: float\n... \n\u003e\u003e\u003e class Circle(TypedDict):\n...     type: Literal['circle']\n...     center: Point2D  # a nested TypedDict!\n...     radius: float\n... \n\u003e\u003e\u003e checkcast(Circle, {\"type\": \"circle\", \"center\": {\"x\": 1}, \"radius\": 10})\nTraceback (most recent call last):\n  ...\ntrycast.ValidationError: Expected Circle but found {'type': 'circle', 'center': {'x': 1}, 'radius': 10}\n  At key 'center': Expected Point2D but found {'x': 1}\n    Required key 'y' is missing\n\u003e\u003e\u003e \n```\n\n`ValidationError` only spends time generating a message if you try to print it\nor stringify it, so can be cheaply caught if you only want to use it for\ncontrol flow purposes.\n\n\n### isassignable()\n\nHere is an example of parsing a `Shape` object defined as a union of\n`TypedDict`s using `isassignable()`:\n\n```python\nclass Circle(TypedDict):\n    type: Literal['circle']\n    ...\n\nclass Rect(TypedDict):\n    type: Literal['rect']\n    ...\n\nShape = Circle | Rect  # a Tagged Union!\n\n@route('/draw_shape')\ndef draw_shape_endpoint() -\u003e HTTPResponse:\n    request_json = request.json  # type: object\n    if not isassignable(request_json, Shape):\n        return HTTPResponse(status=400)  # Bad Request\n    draw_shape(request_json)  # type is narrowed to Shape\n    return HTTPResponse(status=200)  # OK\n```\n\n\u003e **Important:** Current limitations in the mypy typechecker prevent the\n\u003e automatic narrowing of the type of `request_json` in the above example to\n\u003e `Shape`, so you must add an additional `cast()` to narrow the type manually:\n\u003e \n\u003e ```python\n\u003e if not isassignable(request_json, Shape):\n\u003e     ...\n\u003e shape = cast(Shape, request_json)  # type is manually narrowed to Shape\n\u003e draw_shape(shape)\n\u003e ```\n\u003e \n\u003e These limitations are in the process of being resolved by\n\u003e [introducing TypeForm support to mypy](https://github.com/python/mypy/issues/9773).\n\n\n#### A better `isinstance()`\n\n`isassignable(value, T)` is similar to Python's builtin `isinstance()` but\nadditionally supports checking against arbitrary type annotation objects\nincluding TypedDicts, Unions, Literals, and many others.\n\nFormally, `isassignable(value, T)` checks whether `value` is consistent with a \nvariable of type `T` (using [PEP 484](https://peps.python.org/pep-0484/) static\ntypechecking rules), but at *runtime*.\n\n\n## Motivation \u0026 Alternatives\n\n### Why use trycast?\n\nThe trycast module is primarily designed for **recognizing JSON-like structures**\nthat can be described by Python's typing system. Secondarily, it can be used \nfor **recognizing arbitrary structures** that can be described by \nPython's typing system.\n\nPlease see [Philosophy] for more information about how trycast\ndiffers from similar libraries like pydantic.\n\n[Philosophy]: https://github.com/davidfstr/trycast/wiki/Philosophy\n\n### Why use TypedDict?\n\nTyped dictionaries are the natural form that JSON data comes in over the wire.\nThey can be trivially serialized and deserialized without any additional logic.\nFor applications that use a lot of JSON data - such as web applications - \nusing typed dictionaries is very convenient for representing data structures.\n\nIf you just need a lightweight class structure that doesn't need excellent\nsupport for JSON-serialization you might consider other alternatives for\nrepresenting data structures in Python such as [dataclasses] (**recommended**),\n[named tuples], [attrs], or plain classes.\n\n[dataclasses]: https://www.python.org/dev/peps/pep-0557/#abstract\n[named tuples]: https://docs.python.org/3/library/typing.html#typing.NamedTuple\n[attrs]: https://www.attrs.org/en/stable/\n\n\n## Installation\n\n```shell\npython -m pip install trycast\n```\n\n\n## Recommendations while using trycast\n\n- So that `trycast()` can recognize TypedDicts with mixed required and\n  not-required keys correctly:\n    * Use Python 3.9+ if possible.\n    * Prefer using `typing.TypedDict`, unless you must use Python 3.8.\n      In Python 3.8 prefer `typing_extensions.TypedDict` instead.\n    * Avoid using `mypy_extensions.TypedDict` in general.\n\n\n## Presentations \u0026 Videos\n\nA presentation about **using trycast to parse JSON** was given at the\n2021 PyCon US Typing Summit:\n\n[![2021 PyCon US Typing Summit Presentation](https://raw.githubusercontent.com/davidfstr/trycast/main/README/TypingSummit2021_Presentation_FirstSlide.png)](https://youtu.be/ld9rwCvGdhc?t=1782)\n\nA presentation describing **tools that use Python type annotations at runtime**,\nincluding trycast, was given at the 2022 PyCon US Typing Summit:\n\n[![2022 PyCon US Typing Summit Presentation](https://raw.githubusercontent.com/davidfstr/trycast/main/README/TypingSummit2022_Presentation_FirstSlide.png)](https://youtu.be/CmXQOoiMy-g)\n\n## Contributing\n\nPull requests are welcome! The [Python Community Code of Conduct] does apply.\n\n[Python Community Code of Conduct]: https://www.python.org/psf/conduct/\n\nYou can checkout the code locally using:\n\n```\ngit clone git@github.com:davidfstr/trycast.git\ncd trycast\n```\n\nCreate your local virtual environment to develop in using [Poetry]:\n\n[Poetry]: https://python-poetry.org/\n\n```\npoetry shell\npoetry install\n```\n\nYou can run the existing automated tests in the current version of Python with:\n\n```\nmake test\n```\n\nYou can also run the tests against *all* supported Python versions with:\n\n```\nmake testall\n```\n\nSee additional development commands by running:\n\n```\nmake help\n```\n\n\n## License\n\n[MIT](LICENSE.md)\n\n\n## Feature Reference\n\n### Typing Features Supported\n\n* Scalars\n    * bool\n    * int\n    * float\n    * None, type(None)\n* Strings\n    * str\n* Raw Collections\n    * list, List\n    * tuple, Tuple\n    * Sequence, MutableSequence\n    * dict, Dict\n    * Mapping, MutableMapping\n* Generic Collections\n  (including [PEP 585](https://peps.python.org/pep-0585/))\n    * list[T], List[T]\n    * tuple[T, ...], Tuple[T, ...]\n    * Sequence[T], MutableSequence[T]\n    * dict[K, V], Dict[K, V]\n    * Mapping[K, V], MutableMapping[K, V]\n* TypedDict\n    * typing.TypedDict, typing_extensions.TypedDict\n      ([PEP 589](https://peps.python.org/pep-0589/))\n    * mypy_extensions.TypedDict (when strict=False)\n    * –––\n    * Required, NotRequired\n      ([PEP 655](https://peps.python.org/pep-0655/))\n    * ReadOnly\n      ([PEP 705](https://peps.python.org/pep-0705/))\n* Tuples (Heterogeneous)\n    * tuple[T1], tuple[T1, T2], tuple[T1, T2, T3], etc\n    * Tuple[T1], Tuple[T1, T2], Tuple[T1, T2, T3], etc\n* Unions\n    * Union[X, Y]\n    * Optional[T]\n    * X | Y\n      ([PEP 604](https://peps.python.org/pep-0604/))\n* Literals\n    * Literal[value]\n      ([PEP 586](https://peps.python.org/pep-0586/))\n* Callables\n    * Callable\n    * Callable[P, R] (where P=[Any]\\*N and R=Any)\n* NewTypes (when strict=False)\n* Special Types\n    * Any\n    * Never\n    * NoReturn\n\n### Type Checkers Supported\n\nTrycast does type check successfully with the following type checkers:\n\n* [Mypy]\n* [Pyright] / [Pylance]\n* [Pyre]\n* [Pytype]\n\n\n## API Reference\n\n\u003ca name=\"trycast-api\"\u003e\u003c/a\u003e\n### trycast API\n\n```\ndef trycast(\n    tp: TypeForm[T]† | TypeFormString[T]‡,\n    value: object,\n    /, failure: F = None,\n    *, strict: bool = True,\n    eval: bool = True\n) -\u003e T | F: ...\n```\n\nIf `value` is in the shape of `tp` (as accepted by a Python typechecker\nconforming to PEP 484 \"Type Hints\") then returns it, otherwise returns\n`failure` (which is None by default).\n\nThis method logically performs an operation similar to:\n\n```\nreturn value if isinstance(tp, value) else failure\n```\n\nexcept that it supports many more types than `isinstance`, including:\n\n* List[T]\n* Dict[K, V]\n* Optional[T]\n* Union[T1, T2, ...]\n* Literal[...]\n* T extends TypedDict\n\nSimilar to isinstance(), this method considers every bool value to\nalso be a valid int value, as consistent with Python typecheckers:\n\n\u003e trycast(int, True) -\u003e True  \n\u003e isinstance(True, int) -\u003e True\n\nNote that unlike isinstance(), this method considers every int value to\nalso be a valid float or complex value, as consistent with Python typecheckers:\n\n\u003e trycast(float, 1) -\u003e 1  \n\u003e trycast(complex, 1) -\u003e 1  \n\u003e isinstance(1, float) -\u003e False  \n\u003e isinstance(1, complex) -\u003e False\n\nNote that unlike isinstance(), this method considers every float value to\nalso be a valid complex value, as consistent with Python typecheckers:\n\n\u003e trycast(complex, 1.0) -\u003e 1  \n\u003e isinstance(1.0, complex) -\u003e False\n\nParameters:\n\n* **strict** -- \n    * If strict=False then this function will additionally accept\n      mypy_extensions.TypedDict instances and Python 3.8 typing.TypedDict\n      instances for the `tp` parameter. Normally these kinds of types are\n      rejected with a TypeNotSupportedError because these\n      types do not preserve enough information at runtime to reliably\n      determine which keys are required and which are potentially-missing.\n    * If strict=False then `NewType(\"Foo\", T)` will be treated\n      the same as `T`. Normally NewTypes are rejected with a\n      TypeNotSupportedError because values of NewTypes at runtime\n      are indistinguishable from their wrapped supertype.\n* **eval** --\n  If eval=False then this function will not attempt to resolve string\n  type references, which requires the use of the eval() function.\n  Otherwise string type references will be accepted.\n\nRaises:\n\n* **TypeNotSupportedError** --\n    * If strict=True and either mypy_extensions.TypedDict or a\n      Python 3.8 typing.TypedDict is found within the `tp` argument.\n    * If strict=True and a NewType is found within the `tp` argument.\n    * If a TypeVar is found within the `tp` argument.\n    * If an unrecognized Generic type is found within the `tp` argument.\n* **UnresolvedForwardRefError** --\n  If `tp` is a type form which contains a ForwardRef.\n* **UnresolvableTypeError** --\n  If `tp` is a string that could not be resolved to a type.\n\nFootnotes:\n\n* † TypeForm[T] is a [type annotation object]. For example: `list[str]`\n\n* ‡ TypeFormString[T] is a stringified [type annotation object]. For example: `\"list[str]\"`\n\n[type annotation object]: https://github.com/python/mypy/issues/9773\n\n\n### checkcast API\n\n```\ndef checkcast(\n    tp: TypeForm[T]† | TypeFormString[T]‡,\n    value: object,\n    /, *, strict: bool = True,\n    eval: bool = True\n) -\u003e T: ...\n```\n\nIf `value` is in the shape of `tp` (as accepted by a Python typechecker\nconforming to PEP 484 \"Type Hints\") then returns it, otherwise\nraises ValidationError.\n\nThis method logically performs an operation similar to:\n\n```\nif isinstance(tp, value):\n    return value\nelse:\n    raise ValidationError(tp, value)\n```\n\nexcept that it supports many more types than `isinstance`, including:\n\n* List[T]\n* Dict[K, V]\n* Optional[T]\n* Union[T1, T2, ...]\n* Literal[...]\n* T extends TypedDict\n\nSee [trycast.trycast]\\() for information about parameters,\nraised exceptions, and other details.\n\nRaises:\n\n* **ValidationError** -- If `value` is not in the shape of `tp`.\n* **TypeNotSupportedError**\n* **UnresolvedForwardRefError**\n* **UnresolvableTypeError**\n\n[trycast.trycast]: #trycast-api\n\n\n### isassignable API\n\n```\ndef isassignable(\n    value: object,\n    tp: TypeForm[T]† | TypeFormString[T]‡,\n    /, *, eval: bool = True\n) -\u003e TypeGuard[T]: ...\n```\n\nReturns whether `value` is in the shape of `tp`\n(as accepted by a Python typechecker conforming to PEP 484 \"Type Hints\").\n\nThis method logically performs an operation similar to:\n\n```\nreturn isinstance(value, tp)\n```\n\nexcept that it supports many more types than `isinstance`, including:\n\n* List[T]\n* Dict[K, V]\n* Optional[T]\n* Union[T1, T2, ...]\n* Literal[...]\n* T extends TypedDict\n\nSee [trycast.trycast]\\(..., strict=True) for information about parameters,\nraised exceptions, and other details.\n\n[trycast.trycast]: #trycast-api\n\n\n## Changelog\n\n### Future\n\n* See the [Roadmap](https://github.com/davidfstr/trycast/wiki/Roadmap).\n\n### v1.2.0\n\n* Add `checkcast()`, an alternative to `trycast()` which raises a\n  `ValidationError` upon failure instead of returning `None`.\n  ([#16](https://github.com/davidfstr/trycast/issues/16))\n* Add support for Python 3.13.\n    * Recognize `ReadOnly[]` from PEP 705.\n      ([#25](https://github.com/davidfstr/trycast/issues/25))\n* Add support for Python 3.12.\n    * Recognize `type` statements from PEP 695.\n      ([#29](https://github.com/davidfstr/trycast/issues/29))\n* Enhance support for Python 3.11:\n    * Recognize special `Never` values.\n      ([#26](https://github.com/davidfstr/trycast/issues/26))\n* Drop support for Python 3.7. ([#21](https://github.com/davidfstr/trycast/issues/21))\n* Enforce that calls to `trycast()` and `isassignable()` pass the\n  first 2 arguments in positional fashion and not in a named fashion:\n  ([#18](https://github.com/davidfstr/trycast/issues/18))\n  **(Breaking change)**\n    * Yes: `trycast(T, value)`, `isassignable(value, T)`\n    * No: `trycast(tp=T, value=value)`, `isassignable(value=value, tp=T)`\n\n### v1.1.0\n\n* Fix `trycast()` to recognize TypedDicts with extra keys. ([#19](https://github.com/davidfstr/trycast/issues/19))\n    * This new behavior helps recognize JSON structures with arbitrary additional keys\n      and is consistent with how static typecheckers treat additional keys.\n* Fix magic wand in logo to look more like a magic wand. ([#20](https://github.com/davidfstr/trycast/issues/20))\n\n### v1.0.0\n\n* Extend `trycast()` to recognize more kinds of types:\n    * Extend `trycast()` to recognize `set[T]` and `Set[T]` values.\n    * Extend `trycast()` to recognize `frozenset[T]` and `FrozenSet[T]` values.\n    * Extend `trycast()` to recognize `Callable` and `Callable[P, R]` types when `P` and `R` only contain `Any`.\n    * Extend `trycast()` to recognize `NewType` types when strict=False.\n    * Extend `trycast()` to explicitly disallow `TypeVar` types.\n    * Extend `trycast()` to explicitly disallow unrecognized `Generic` types.\n* Fix issues with PEP 484 conformance: **(Breaking change)**\n    * `bool` values are now correctly treated as assignable to `int`.\n    * `bool`, `int`, and `float` values are now correctly treated as assignable to `complex`.\n* Add support for Python 3.11.\n* Documentation improvements:\n    * Add installation instructions.\n    * Improve differentiation from similar libraries.\n    * Document supported typing features \u0026 type checkers.\n    * Mention that trycast() and isassignable() accept TypeFormString[T]\n      in addition to TypeForm[T].\n    * Add developer documentation.\n\n### v0.7.3\n\n* Support X|Y syntax for Union types from \n  [PEP 604](https://peps.python.org/pep-0604/).\n* Documentation improvements:\n    * Improve introduction.\n    * Add API reference.\n\n### v0.7.2\n\n* Add logo.\n\n### v0.7.1\n\n* Upgrade development status from Beta to Production/Stable: 🎉\n    * trycast is thoroughly tested.\n    * trycast has high code coverage (98%, across Python 3.7-3.10).\n    * trycast has been in production use for over a year\n      at [at least one company] without issues.\n    * trycast supports all major Python type checkers\n      (Mypy, Pyright/Pylance, Pyre, Pytype).\n    * trycast's initial API is finalized.\n* Fix `coverage` to be a dev-dependency rather than a regular dependency.\n\n### v0.7.0\n\n* Finalize the initial API:\n    * Alter `trycast()` to use `strict=True` by default rather than\n      `strict=False`. **(Breaking change)**\n    * Define trycast's `__all__` to export only the\n      `trycast` and `isassignable` functions.\n* Add support for additional type checkers, in addition to [Mypy]:\n    * Add support for the [Pyright] type checker and\n      [Pylance] language server extension (for Visual Studio Code).\n    * Add support for the [Pyre] type checker.\n    * Add support for the [Pytype] type checker.\n* Extend `trycast()` to recognize special `Any` and `NoReturn` values.\n* Fix `trycast()` to provide better diagnostic error when given a tuple\n  of types as its `tp` argument. Was broken in v0.6.0.\n\n[Mypy]: http://mypy-lang.org/\n[Pyright]: https://github.com/microsoft/pyright#readme\n[Pylance]: https://github.com/microsoft/pylance-release#readme\n[Pyre]: https://pyre-check.org/\n[Pytype]: https://google.github.io/pytype/\n\n### v0.6.1\n\n* Fix `trycast(..., eval=False)` to not use `typing.get_type_hints()`,\n  which internally calls `eval()`.\n* Fix `trycast()` and `isassignable()` to avoid swallowing KeyboardInterrupt\n  and other non-Exception BaseExceptions.\n\n### v0.6.0\n\n* Extend `trycast()` to recognize a stringified type argument.\n* Extend `trycast()` to report a better error message when given\n  a type argument with an unresolved forward reference (`ForwardRef`).\n* Fix `strict` argument to `trycast` to be passed to inner calls of `trycast`\n  correctly.\n    * This also fixes `isassignable()`'s use of strict matching to be correct.\n* Alter `trycast()` to interpret a type argument of `None` or `\"None\"` as an\n  alias for `type(None)`, as consistent with\n  [PEP 484](https://peps.python.org/pep-0484/#using-none).\n* Alter `TypeNotSupportedError` to extend `TypeError` rather than `ValueError`.\n  **(Breaking change)**\n    * This is consistent with `trycast`'s and `isinstance`'s behavior of using\n      a `TypeError` rather than a `ValueError` when there is a problem with its\n      `tp` argument.\n* Drop support for Python 3.6. **(Breaking change)**\n    * Python 3.6 is end-of-life.\n\n### v0.5.0\n\n* `isassignable()` is introduced to the API:\n    * `isassignable()` leverages `trycast()` to enable type-checking\n      of values against type objects (i.e. type forms) provided at\n      runtime, using the same PEP 484 typechecking rules used by\n      typecheckers such as mypy.\n* Extend `trycast()` to recognize `Required[]` and `NotRequired[]` from\n  [PEP 655], as imported from `typing_extensions`.\n* Extend `trycast()` to support a `strict` parameter that controls whether it\n  accepts `mypy_extensions.TypedDict` or Python 3.8 `typing.TypedDict`\n  instances (which lack certain runtime type information necessary for\n  accurate runtime typechecking).\n    * For now `strict=False` by default for backward compatibility\n      with earlier versions of `trycast()`, but this default is expected\n      to be altered to `strict=True` when/before trycast v1.0.0 is released.\n* Rename primary development branch from `master` to `main`.\n\n[PEP 655]: https://www.python.org/dev/peps/pep-0655/\n\n### v0.4.0\n\n* Upgrade development status from Alpha to Beta:\n    * trycast is thoroughly tested.\n    * trycast has high code coverage (92% on Python 3.9).\n    * trycast has been in production use for over a year\n      at [at least one company] without issues.\n* Add support for Python 3.10.\n* Setup continuous integration with GitHub Actions, against Python 3.6 - 3.10.\n* Migrate to the Black code style.\n* Introduce Black and isort code formatters.\n* Introduce flake8 linter.\n* Introduce coverage.py code coverage reports.\n\n[at least one company]: https://dafoster.net/projects/techsmart-platform/\n\n### v0.3.0\n\n* TypedDict improvements \u0026 fixes:\n    * Fix `trycast()` to recognize custom Mapping subclasses as TypedDicts.\n* Extend `trycast()` to recognize more JSON-like values:\n    * Extend `trycast()` to recognize `Mapping` and `MutableMapping` values.\n    * Extend `trycast()` to recognize `tuple[T, ...]` and `Tuple[T, ...]` values.\n    * Extend `trycast()` to recognize `Sequence` and `MutableSequence` values.\n* Extend `trycast()` to recognize `tuple[T1, T2, etc]` and `Tuple[T1, T2, etc]` values.\n* Documentation improvements:\n    * Improve introduction.\n    * Outline motivation to use trycast and note alternatives.\n\n### v0.2.0\n\n* TypedDict improvements \u0026 fixes:\n    * Fix `trycast()` to recognize TypedDicts from `mypy_extensions`.\n    * Extend `trycast()` to recognize TypedDicts that contain forward-references\n      to other types.\n        - Unfortunately there appears to be no easy way to support arbitrary kinds\n          of types that contain forward-references.\n        - In particular {Union, Optional} types and collection types (List, Dict)\n          with forward-references remain unsupported by `trycast()`.\n    * Recognize TypedDicts that have mixed required and not-required keys correctly.\n        - Exception: Does not work for mypy_extensions.TypedDict or\n          Python 3.8's typing.TypedDict due to insufficient runtime\n          type annotation information.\n    * Fix recognition of a total=False TypedDict so that extra keys are disallowed.\n* Alter `typing_extensions` to be an optional dependency of `trycast`.\n\n### v0.1.0\n\n* Add support for Python 3.6, 3.7, and 3.9, in addition to 3.8.\n\n### v0.0.2\n\n* Fix README to appear on PyPI.\n* Add other package metadata, such as the supported Python versions.\n\n### v0.0.1a\n\n* Initial release.\n* Supports typechecking all types found in JSON.\n","funding_links":[],"categories":["Python","Dynamic type checkers"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidfstr%2Ftrycast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavidfstr%2Ftrycast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidfstr%2Ftrycast/lists"}