-
Notifications
You must be signed in to change notification settings - Fork 123
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
Add a contrib module to generate type hints for capnp schemas #289
Conversation
This pull request introduces 1 alert when merging a8f18ca into e93b045 - view on LGTM.com new alerts:
|
I'm still interested in this. Will need to get the CI issues fixed. |
@haata I am still working on it, but I decided to rewrite it. Testing the original implementation against Since my rewrite causes increased complexity and modularization, this can also become a standalone package with its own CLI. The CLI takes:
Then, it creates type hints for all matching schemas, as well as a |
@haata Here is an example. Please let me know, if you would add some important methods that I might have missed. This was generated using the following command line call: Consider this nested schema
alongside this
The output of the stub generator is currently this """This is an automatically generated stub for `ex.capnp`."""
from __future__ import annotations
from contextlib import contextmanager
from io import BufferedWriter
from typing import Iterator, List, Literal, Union, overload
from .ex_imp_capnp import TestImport
class TestNestedTypes:
class NestedStruct:
NestedEnum1 = Literal["foo", "bar"]
NestedEnum2 = Literal["baz", "qux", "quux"]
outerNestedEnum: TestNestedTypes.NestedStruct.NestedEnum1
innerNestedEnum: TestNestedTypes.NestedStruct.NestedEnum2
listOuterNestedEnum: List[TestNestedTypes.NestedStruct.NestedEnum1]
listInnerNestedEnum: List[TestNestedTypes.NestedStruct.NestedEnum2]
@staticmethod
@contextmanager
def from_bytes(
data: bytes, traversal_limit_in_words: Union[int, None] = ..., nesting_limit: Union[int, None] = ...
) -> Iterator[TestNestedTypes.NestedStructReader]: ...
def to_bytes(self) -> bytes: ...
@staticmethod
def new_message() -> TestNestedTypes.NestedStructBuilder: ...
class NestedStructReader(TestNestedTypes.NestedStruct):
def as_builder(self) -> TestNestedTypes.NestedStructBuilder: ...
class NestedStructBuilder(TestNestedTypes.NestedStruct):
def as_reader(self) -> TestNestedTypes.NestedStructReader: ...
@staticmethod
def write(file: BufferedWriter) -> None: ...
nestedStruct: TestNestedTypes.NestedStruct
outerNestedEnum: TestNestedTypes.NestedStruct.NestedEnum1
innerNestedEnum: TestNestedTypes.NestedStruct.NestedEnum2
someListofList: List[List[List[TestNestedTypes.NestedStruct.NestedEnum1]]]
importedVariable: TestImport
@overload
def init(self, name: Literal["nestedStruct"]) -> TestNestedTypes.NestedStruct: ...
@overload
def init(self, name: Literal["importedVariable"]) -> TestImport: ...
@staticmethod
@contextmanager
def from_bytes(
data: bytes, traversal_limit_in_words: Union[int, None] = ..., nesting_limit: Union[int, None] = ...
) -> Iterator[TestNestedTypesReader]: ...
def to_bytes(self) -> bytes: ...
@staticmethod
def new_message() -> TestNestedTypesBuilder: ...
class TestNestedTypesReader(TestNestedTypes):
def as_builder(self) -> TestNestedTypesBuilder: ...
class TestNestedTypesBuilder(TestNestedTypes):
def as_reader(self) -> TestNestedTypesReader: ...
@staticmethod
def write(file: BufferedWriter) -> None: ... And this """This is an automatically generated stub for `ex.capnp`."""
import os
import capnp # type: ignore
capnp.remove_import_hook()
here = os.path.dirname(os.path.abspath(__file__))
module_file = os.path.abspath(os.path.join(here, "ex.capnp"))
TestNestedTypes = capnp.load(module_file).TestNestedTypes
TestNestedTypesBuilder = TestNestedTypes
TestNestedTypesReader = TestNestedTypes This is the generated stub """This is an automatically generated stub for `ex_imp.capnp`."""
from __future__ import annotations
from contextlib import contextmanager
from io import BufferedWriter
from typing import Iterator, Union
class TestImport:
aVariable: float
@staticmethod
@contextmanager
def from_bytes(
data: bytes, traversal_limit_in_words: Union[int, None] = ..., nesting_limit: Union[int, None] = ...
) -> Iterator[TestImportReader]: ...
def to_bytes(self) -> bytes: ...
@staticmethod
def new_message() -> TestImportBuilder: ...
class TestImportReader(TestImport):
def as_builder(self) -> TestImportBuilder: ...
class TestImportBuilder(TestImport):
def as_reader(self) -> TestImportReader: ...
@staticmethod
def write(file: BufferedWriter) -> None: ... And the """This is an automatically generated stub for `ex_imp.capnp`."""
import os
import capnp # type: ignore
capnp.remove_import_hook()
here = os.path.dirname(os.path.abspath(__file__))
module_file = os.path.abspath(os.path.join(here, "ex_imp.capnp"))
TestImport = capnp.load(module_file).TestImport
TestImportBuilder = TestImport
TestImportReader = TestImport |
Is this PR still maintained? What are the current remaining issues? |
@brainslush Yes, it is! I will submit a new version of it soon, as I have been optimizing it in a production environment. A lot of bugs have popped up over time, so the module wasn't really ready for many kinds of schemas. |
This would be wonderful to have! It's very tedious working with pycapnp with no editor assistance. |
Sorry to keep you waiting, I will try to bring something up as fast as possible |
Please check https://gitlab.com/mic_public/tools/python-helpers/capnp-stub-generator This will probably not be the final place/shape for release, but we have been using it successfully like this. For now I will close this merge request, because this is an entirely separate tool. |
Cool! I've added a link in the top-level README. https://github.com/capnproto/pycapnp/tree/ed894304a34ce28254779ea5215afe942a0d5b31#stub-file-generation Longer term it may make more sense to integrate this directly under https://github.com/orgs/capnproto. But there is no rush for this. |
Great, thanks for adding it! I agree, it would be better to integrate it directly. However, it might need to stay as a standalone package and command-line tool, since it is too complex to be put into just a single script. |
This is awesome, thank you for sharing @elagil! |
@loloxwg Yes, it's actually not published on the public pypi server, only on our company internal server. I will fix that soon. In the mean time, just clone the repository and install it with pip from the local source. |
You can also let pip clone it:
|
Since there is no movement in #260, I decided to pick up that pull request and fix remaining CI issues.
Update: This is now a separate application, see #289 (comment)