Python-Interoperability for Typescript-Interfaces
Project description
ts2python
Python-interoperability for Typescript-Interfaces. Transpiles TypeScript-Interface-definitions to Python TypedDicts, plus support for run-time type-checking of JSON-data.
License
ts2python is open source software under the Apache 2.0 License
Copyright 2021 Eckhart Arnold arnold@badw.de, Bavarian Academy of Sciences and Humanities
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Purpose
When processing JSON data, as for example form a JSON-RPC call, with Python, it would be helpful to have Python-definitions of the JSON-structures at hand, in order to solicit IDE-Support, static type checking and, potentially to enable structural validation at runtime.
There exist different technologies for defining the structure of JSON-data. Next to JSON-schema, a de facto very popular technology for defining JSON-obejcts are Typescript-Interfaces. For example, the language server protocol defines the structure of the JSON-data exchanged between client and server with Typescript-Interfaces.
In order to enable structural validation on the Python-side, ts2python transpiles the typescript-interface definitions to Python-data structure definitions, primarily, TypedDicts, but with some postprocessing it can also be adjusted to other popular models for records or data structures in Python, e.g. pydantic-Classes and the like.
Installation
ts2python can be installed from the command line with the command:
# pip install ts2python
ts2python requires the parsing-expression-grammar-framwork
DHParser
which will automatically be installed as a dependency by
the pip
-command. ts2python requires at least Python Version 3.8
to run. (If there is any interest, I might backport it to Python 3.6.)
However, the Python-code it produces is backwards compatible
down to Python 3.6, if the
typing extensions
have been installed.
For a demonstration how the TypeScript-Interfaces are transpiled
to Python-code, run the demo.sh
-script (or demo.bat
on Windows)
in the "demo"-sub-directory or the ts2python-directory.
Or, run the tst_ts2python_gramm.py
in the ts2python-directory
and look up the grammar-test-reports in the "REPORT"-sub-directory
of the "test_grammar"-subdirectory.
Usage
In order to generate TypedDict-classes from Typescript-Interfaces,
run ts2python
on the Typescript-Interface definitions:
# ts2python interfaces.ts
This generates a .py-file in same directory as the source file that contains the TypedDict-classes and can simpy be imported in Python-Code:
>>> from interface_definitions import *
Other data-representation models than TypedDict can be supported
with the --base
and --decorator
-options, e.g.
>>> ts2python --base pydantic.BaseModel interfaces.ts
or:
>>> ts2python --decorator attr.s interfaces.ts
Presently, ts2python does only offer very rudimentary support for other models than TypedDict. So, before it can be used, further adjustments to the generated file are necessary when using data models other than TypedDict.
Validation
ts2python ships support for runtime-type validation. While type errors can be detected by static type checkers, runtime type validation can be useful when processing data from an outside source which cannot statically be checked, like, for example, json-data stemming from an RPC-call. ts2python runtime-type validation can be invoked via dedicated functions or via decorator as in this example:
from ts2python.json_validation import TypedDict, type_check
class Position(TypedDict, total=True):
line: int
character: int
class Range(TypedDict, total=True):
start: Position
end: Position
@type_check
def middle_line(rng: Range) -> Position:
line = (rng['start']['line'] + rng['end']['line']) // 2
character = 0
return Position(line=line, character=character)
data = {'start': {'line': 1, 'character': 1},
'end': {'line': 8, 'character': 17}}
assert middle_line(data) == {'line': 4, 'character': 0}
malformed_data = {'start': 1, 'end': 8}
middle_line(malformed_data) # <- TypeError raised by @type_check
With the type decorator the last call fails with a TypeError:
TypeError: Parameter "rng" of function "middle_line" failed the type-check, because:
Type error(s) in dictionary of type <class '__main__.Range'>:
Field start: '1' is not of <class '__main__.Position'>, but of type <class 'int'>
Field end: '8' is not of <class '__main__.Position'>, but of type <class 'int'>
Both the call and the return types can be validated.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.