diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 49ef886..1310c5c 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1,30 +1,46 @@ jobs: arrange: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - run: test -z "$(goarrange run -d)" + black: + container: ghcr.io/elimity-com/insights-sdk:18279107697 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - run: poetry install + - run: poetry run black --check src + buf-generate: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - - run: npm ci - - run: npx buf generate + - run: buf generate + - run: poetry install + - run: poetry run protol -o gen/elimity --create-package --in-place buf + - run: touch gen/elimity/py.typed - run: git -c safe.directory=/__w/insights-sdk/insights-sdk diff --quiet buf-lint: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - - run: npm ci - - run: npx buf lint + - run: buf lint + + check: + container: ghcr.io/elimity-com/insights-sdk:18279107697 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - run: poetry check --lock eslint: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -32,14 +48,30 @@ jobs: - run: npx eslint . golangci-lint: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - run: GOFLAGS='-buildvcs=false' golangci-lint run + isort: + container: ghcr.io/elimity-com/insights-sdk:18279107697 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - run: poetry install + - run: poetry run isort -c src + + mypy: + container: ghcr.io/elimity-com/insights-sdk:18279107697 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - run: poetry install + - run: poetry run mypy src + prettier: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -47,21 +79,21 @@ jobs: - run: npx prettier -c . test: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - run: go test -v ./... tidy: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - run: go mod tidy -diff tsc: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0932637..037fd93 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,6 @@ jobs: job: - container: ghcr.io/elimity-com/insights-sdk:14245239418 + container: ghcr.io/elimity-com/insights-sdk:18279107697 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -8,6 +8,8 @@ jobs: - run: npm version --no-git-tag-version ${{ github.event.release.tag_name }} - run: npx tsc - run: env NPM_CONFIG_//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} npm publish --access public + - run: poetry version $(poetry version -s --dry-run ${{ github.event.release.tag_name }}) + - run: POETRY_PYPI_TOKEN_PYPI=${{ secrets.PYPI_TOKEN }} poetry publish --build on: release: diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..f238bf7 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile = black diff --git a/Dockerfile b/Dockerfile index 15a1d18..c0f8dfa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,9 @@ -FROM node:lts +FROM node:lts-trixie ARG TARGETARCH -ENV PATH=$PATH:/root/go/bin:/usr/local/go/bin +ENV PATH=$PATH:/root/.local/bin:/root/go/bin:/usr/local/go/bin RUN \ curl -L https://go.dev/dl/go1.24.1.linux-$TARGETARCH.tar.gz | tar -C /usr/local -xz && \ + curl https://install.python-poetry.org | python3 && \ curl https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh && \ + go install github.com/bufbuild/buf/cmd/buf@latest && \ go install github.com/jdeflander/goarrange@latest diff --git a/README.md b/README.md index a1f02e9..a9f5ac8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Elimity Insights SDK -This repository contains a Go and NodeJS package to simplify the implementation of various interactions with Elimity -Insights servers. +This repository contains a Go, NodeJS and Python package to simplify the implementation of various interactions with +Elimity Insights servers. ## Usage @@ -165,6 +165,58 @@ const sdkHandler = handler(generateItems); express().use(authHandler, sdkHandler).listen(8080); ``` +### Python + +```python +from collections.abc import AsyncIterator +from os import listdir +from typing import Literal + +from auth0_api_python import ApiClient, ApiClientOptions +from elimity_insights_sdk import EntityItem, Item, Level, LogItem, Value, app +from pydantic import BaseModel +from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint +from starlette.requests import Request +from starlette.responses import Response +from uvicorn import run + +_options = ApiClientOptions("auth.elimity.com", "gateway") +_client = ApiClient(_options) + + +class _Claims(BaseModel): + base_url: Literal["https://example.elimity.com"] + gateway_url: Literal["https://gateway.example.com"] + source_id: Literal["42"] + + +class _Middleware(BaseHTTPMiddleware): + async def dispatch( + self, request: Request, call_next: RequestResponseEndpoint + ) -> Response: + headers = dict(request.headers) + claims = await _client.verify_request(headers) + _Claims.model_validate(claims) + return await call_next(request) + + +class _Request(BaseModel): + path: str + + +async def _generate_items(fields: dict[str, object]) -> AsyncIterator[Item]: + request = _Request.model_validate(fields) + yield LogItem(Level.INFO, "Reading directory contents") + for file in listdir(request.path): + assignments: dict[str, Value] = {} + yield EntityItem(assignments, file, file, "file") + + +_app = app(_generate_items) +_middleware = _Middleware(_app) +run(_middleware) +``` + ## Installation ### Go @@ -179,6 +231,12 @@ $ go get github.com/elimity-com/insights-sdk $ npm i @elimity/insights-sdk ``` +### Python + +``` +$ pip install elimity-insights-sdk +``` + ## Compatibility | SDK version | Insights version | diff --git a/buf.gen.yaml b/buf.gen.yaml index c786851..2ef4803 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -16,4 +16,13 @@ plugins: out: gen remote: buf.build/connectrpc/es:v1.6.1 revision: 1 + - out: gen + remote: buf.build/connectrpc/python:v0.5.0 + revision: 1 + - out: gen + remote: buf.build/protocolbuffers/pyi:v29.5 + revision: 1 + - out: gen + remote: buf.build/protocolbuffers/python:v29.5 + revision: 1 version: v2 diff --git a/docker-compose.yml b/docker-compose.yml index 52a0230..8579303 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: dev: entrypoint: sleep infinity - image: ghcr.io/elimity-com/insights-sdk:14245239418 + image: ghcr.io/elimity-com/insights-sdk:18279107697 init: true volumes: - .:/app diff --git a/gen/elimity/__init__.py b/gen/elimity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/__init__.pyi b/gen/elimity/__init__.pyi new file mode 100644 index 0000000..cf88340 --- /dev/null +++ b/gen/elimity/__init__.pyi @@ -0,0 +1 @@ +from . import insights diff --git a/gen/elimity/insights/__init__.py b/gen/elimity/insights/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/__init__.pyi b/gen/elimity/insights/__init__.pyi new file mode 100644 index 0000000..30cad0e --- /dev/null +++ b/gen/elimity/insights/__init__.pyi @@ -0,0 +1,3 @@ +from . import common +from . import customgateway +from . import export diff --git a/gen/elimity/insights/common/__init__.py b/gen/elimity/insights/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/common/__init__.pyi b/gen/elimity/insights/common/__init__.pyi new file mode 100644 index 0000000..374b089 --- /dev/null +++ b/gen/elimity/insights/common/__init__.pyi @@ -0,0 +1 @@ +from . import v1alpha1 diff --git a/gen/elimity/insights/common/v1alpha1/__init__.py b/gen/elimity/insights/common/v1alpha1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/common/v1alpha1/__init__.pyi b/gen/elimity/insights/common/v1alpha1/__init__.pyi new file mode 100644 index 0000000..44c1708 --- /dev/null +++ b/gen/elimity/insights/common/v1alpha1/__init__.pyi @@ -0,0 +1 @@ +from . import common_pb2 diff --git a/gen/elimity/insights/common/v1alpha1/common_pb2.py b/gen/elimity/insights/common/v1alpha1/common_pb2.py new file mode 100644 index 0000000..7f167b5 --- /dev/null +++ b/gen/elimity/insights/common/v1alpha1/common_pb2.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: elimity/insights/common/v1alpha1/common.proto +# Protobuf Python Version: 5.29.5 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 29, + 5, + '', + 'elimity/insights/common/v1alpha1/common.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n-elimity/insights/common/v1alpha1/common.proto\x12 elimity.insights.common.v1alpha1\x1a\x1fgoogle/protobuf/timestamp.proto\"\xab\x02\n\x06\x45ntity\x12w\n\x15\x61ttribute_assignments\x18\x01 \x03(\x0b\x32\x42.elimity.insights.common.v1alpha1.Entity.AttributeAssignmentsEntryR\x14\x61ttributeAssignments\x12\x0e\n\x02id\x18\x02 \x01(\tR\x02id\x12\x12\n\x04name\x18\x03 \x01(\tR\x04name\x12\x12\n\x04type\x18\x04 \x01(\tR\x04type\x1ap\n\x19\x41ttributeAssignmentsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12=\n\x05value\x18\x02 \x01(\x0b\x32\'.elimity.insights.common.v1alpha1.ValueR\x05value:\x02\x38\x01\"\x97\x03\n\x0cRelationship\x12}\n\x15\x61ttribute_assignments\x18\x01 \x03(\x0b\x32H.elimity.insights.common.v1alpha1.Relationship.AttributeAssignmentsEntryR\x14\x61ttributeAssignments\x12$\n\x0e\x66rom_entity_id\x18\x02 \x01(\tR\x0c\x66romEntityId\x12(\n\x10\x66rom_entity_type\x18\x03 \x01(\tR\x0e\x66romEntityType\x12 \n\x0cto_entity_id\x18\x04 \x01(\tR\ntoEntityId\x12$\n\x0eto_entity_type\x18\x05 \x01(\tR\x0ctoEntityType\x1ap\n\x19\x41ttributeAssignmentsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12=\n\x05value\x18\x02 \x01(\x0b\x32\'.elimity.insights.common.v1alpha1.ValueR\x05value:\x02\x38\x01\"\xff\x01\n\x05Value\x12\x1a\n\x07\x62oolean\x18\x01 \x01(\x08H\x00R\x07\x62oolean\x12\x30\n\x04\x64\x61te\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00R\x04\x64\x61te\x12\x39\n\tdate_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00R\x08\x64\x61teTime\x12\x18\n\x06number\x18\x04 \x01(\x01H\x00R\x06number\x12\x18\n\x06string\x18\x05 \x01(\tH\x00R\x06string\x12\x30\n\x04time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00R\x04timeB\x07\n\x05valueBJZHgithub.com/elimity-com/insights-sdk/gen/elimity/insights/common/v1alpha1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'elimity.insights.common.v1alpha1.common_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'ZHgithub.com/elimity-com/insights-sdk/gen/elimity/insights/common/v1alpha1' + _globals['_ENTITY_ATTRIBUTEASSIGNMENTSENTRY']._loaded_options = None + _globals['_ENTITY_ATTRIBUTEASSIGNMENTSENTRY']._serialized_options = b'8\001' + _globals['_RELATIONSHIP_ATTRIBUTEASSIGNMENTSENTRY']._loaded_options = None + _globals['_RELATIONSHIP_ATTRIBUTEASSIGNMENTSENTRY']._serialized_options = b'8\001' + _globals['_ENTITY']._serialized_start=117 + _globals['_ENTITY']._serialized_end=416 + _globals['_ENTITY_ATTRIBUTEASSIGNMENTSENTRY']._serialized_start=304 + _globals['_ENTITY_ATTRIBUTEASSIGNMENTSENTRY']._serialized_end=416 + _globals['_RELATIONSHIP']._serialized_start=419 + _globals['_RELATIONSHIP']._serialized_end=826 + _globals['_RELATIONSHIP_ATTRIBUTEASSIGNMENTSENTRY']._serialized_start=304 + _globals['_RELATIONSHIP_ATTRIBUTEASSIGNMENTSENTRY']._serialized_end=416 + _globals['_VALUE']._serialized_start=829 + _globals['_VALUE']._serialized_end=1084 +# @@protoc_insertion_point(module_scope) diff --git a/gen/elimity/insights/common/v1alpha1/common_pb2.pyi b/gen/elimity/insights/common/v1alpha1/common_pb2.pyi new file mode 100644 index 0000000..eea01af --- /dev/null +++ b/gen/elimity/insights/common/v1alpha1/common_pb2.pyi @@ -0,0 +1,63 @@ +from google.protobuf import timestamp_pb2 as _timestamp_pb2 +from google.protobuf.internal import containers as _containers +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union + +DESCRIPTOR: _descriptor.FileDescriptor + +class Entity(_message.Message): + __slots__ = ("attribute_assignments", "id", "name", "type") + class AttributeAssignmentsEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: Value + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ...) -> None: ... + ATTRIBUTE_ASSIGNMENTS_FIELD_NUMBER: _ClassVar[int] + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + TYPE_FIELD_NUMBER: _ClassVar[int] + attribute_assignments: _containers.MessageMap[str, Value] + id: str + name: str + type: str + def __init__(self, attribute_assignments: _Optional[_Mapping[str, Value]] = ..., id: _Optional[str] = ..., name: _Optional[str] = ..., type: _Optional[str] = ...) -> None: ... + +class Relationship(_message.Message): + __slots__ = ("attribute_assignments", "from_entity_id", "from_entity_type", "to_entity_id", "to_entity_type") + class AttributeAssignmentsEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: Value + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ...) -> None: ... + ATTRIBUTE_ASSIGNMENTS_FIELD_NUMBER: _ClassVar[int] + FROM_ENTITY_ID_FIELD_NUMBER: _ClassVar[int] + FROM_ENTITY_TYPE_FIELD_NUMBER: _ClassVar[int] + TO_ENTITY_ID_FIELD_NUMBER: _ClassVar[int] + TO_ENTITY_TYPE_FIELD_NUMBER: _ClassVar[int] + attribute_assignments: _containers.MessageMap[str, Value] + from_entity_id: str + from_entity_type: str + to_entity_id: str + to_entity_type: str + def __init__(self, attribute_assignments: _Optional[_Mapping[str, Value]] = ..., from_entity_id: _Optional[str] = ..., from_entity_type: _Optional[str] = ..., to_entity_id: _Optional[str] = ..., to_entity_type: _Optional[str] = ...) -> None: ... + +class Value(_message.Message): + __slots__ = ("boolean", "date", "date_time", "number", "string", "time") + BOOLEAN_FIELD_NUMBER: _ClassVar[int] + DATE_FIELD_NUMBER: _ClassVar[int] + DATE_TIME_FIELD_NUMBER: _ClassVar[int] + NUMBER_FIELD_NUMBER: _ClassVar[int] + STRING_FIELD_NUMBER: _ClassVar[int] + TIME_FIELD_NUMBER: _ClassVar[int] + boolean: bool + date: _timestamp_pb2.Timestamp + date_time: _timestamp_pb2.Timestamp + number: float + string: str + time: _timestamp_pb2.Timestamp + def __init__(self, boolean: bool = ..., date: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., date_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., number: _Optional[float] = ..., string: _Optional[str] = ..., time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ... diff --git a/gen/elimity/insights/customgateway/__init__.py b/gen/elimity/insights/customgateway/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/customgateway/__init__.pyi b/gen/elimity/insights/customgateway/__init__.pyi new file mode 100644 index 0000000..374b089 --- /dev/null +++ b/gen/elimity/insights/customgateway/__init__.pyi @@ -0,0 +1 @@ +from . import v1alpha1 diff --git a/gen/elimity/insights/customgateway/v1alpha1/__init__.py b/gen/elimity/insights/customgateway/v1alpha1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/customgateway/v1alpha1/__init__.pyi b/gen/elimity/insights/customgateway/v1alpha1/__init__.pyi new file mode 100644 index 0000000..c8fbf39 --- /dev/null +++ b/gen/elimity/insights/customgateway/v1alpha1/__init__.pyi @@ -0,0 +1,2 @@ +from . import customgateway_pb2 +from . import v1alpha1connect diff --git a/gen/elimity/insights/customgateway/v1alpha1/customgateway_connect.py b/gen/elimity/insights/customgateway/v1alpha1/customgateway_connect.py new file mode 100644 index 0000000..66b2bd0 --- /dev/null +++ b/gen/elimity/insights/customgateway/v1alpha1/customgateway_connect.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +# Generated by https://github.com/connectrpc/connect-python. DO NOT EDIT! +# source: elimity/insights/customgateway/v1alpha1/customgateway.proto + +from collections.abc import AsyncIterator, Iterable, Iterator, Mapping +from typing import Protocol + +from connectrpc.client import ConnectClient, ConnectClientSync +from connectrpc.code import Code +from connectrpc.errors import ConnectError +from connectrpc.interceptor import Interceptor, InterceptorSync +from connectrpc.method import IdempotencyLevel, MethodInfo +from connectrpc.request import Headers, RequestContext +from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync +import elimity.insights.customgateway.v1alpha1.customgateway_pb2 as elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2 + + +class Service(Protocol): + def perform_import(self, request: elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, ctx: RequestContext) -> AsyncIterator[elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse]: + raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") + + +class ServiceASGIApplication(ConnectASGIApplication): + def __init__(self, service: Service, *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None) -> None: + super().__init__( + endpoints={ + "/elimity.insights.customgateway.v1alpha1.Service/PerformImport": Endpoint.server_stream( + method=MethodInfo( + name="PerformImport", + service_name="elimity.insights.customgateway.v1alpha1.Service", + input=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, + output=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + function=service.perform_import, + ), + }, + interceptors=interceptors, + read_max_bytes=read_max_bytes, + ) + + @property + def path(self) -> str: + """Returns the URL path to mount the application to when serving multiple applications.""" + return "/elimity.insights.customgateway.v1alpha1.Service" + + +class ServiceClient(ConnectClient): + def perform_import( + self, + request: elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, + *, + headers: Headers | Mapping[str, str] | None = None, + timeout_ms: int | None = None, + ) -> AsyncIterator[elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse]: + return self.execute_server_stream( + request=request, + method=MethodInfo( + name="PerformImport", + service_name="elimity.insights.customgateway.v1alpha1.Service", + input=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, + output=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + headers=headers, + timeout_ms=timeout_ms, + ) + + +class ServiceSync(Protocol): + def perform_import(self, request: elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, ctx: RequestContext) -> Iterator[elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse]: + raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") + + +class ServiceWSGIApplication(ConnectWSGIApplication): + def __init__(self, service: ServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None) -> None: + super().__init__( + endpoints={ + "/elimity.insights.customgateway.v1alpha1.Service/PerformImport": EndpointSync.server_stream( + method=MethodInfo( + name="PerformImport", + service_name="elimity.insights.customgateway.v1alpha1.Service", + input=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, + output=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + function=service.perform_import, + ), + }, + interceptors=interceptors, + read_max_bytes=read_max_bytes, + ) + + @property + def path(self) -> str: + """Returns the URL path to mount the application to when serving multiple applications.""" + return "/elimity.insights.customgateway.v1alpha1.Service" + + +class ServiceClientSync(ConnectClientSync): + def perform_import( + self, + request: elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, + *, + headers: Headers | Mapping[str, str] | None = None, + timeout_ms: int | None = None, + ) -> Iterator[elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse]: + return self.execute_server_stream( + request=request, + method=MethodInfo( + name="PerformImport", + service_name="elimity.insights.customgateway.v1alpha1.Service", + input=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportRequest, + output=elimity_dot_insights_dot_customgateway_dot_v1alpha1_dot_customgateway__pb2.PerformImportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + headers=headers, + timeout_ms=timeout_ms, + ) diff --git a/gen/elimity/insights/customgateway/v1alpha1/customgateway_pb2.py b/gen/elimity/insights/customgateway/v1alpha1/customgateway_pb2.py new file mode 100644 index 0000000..19c0f5f --- /dev/null +++ b/gen/elimity/insights/customgateway/v1alpha1/customgateway_pb2.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: elimity/insights/customgateway/v1alpha1/customgateway.proto +# Protobuf Python Version: 5.29.5 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 29, + 5, + '', + 'elimity/insights/customgateway/v1alpha1/customgateway.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from elimity.insights.common.v1alpha1 import common_pb2 as elimity_dot_insights_dot_common_dot_v1alpha1_dot_common__pb2 +from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 +from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n;elimity/insights/customgateway/v1alpha1/customgateway.proto\x12\'elimity.insights.customgateway.v1alpha1\x1a-elimity/insights/common/v1alpha1/common.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\"n\n\x05Level\x12.\n\x05\x61lert\x18\x01 \x01(\x0b\x32\x16.google.protobuf.EmptyH\x00R\x05\x61lert\x12,\n\x04info\x18\x02 \x01(\x0b\x32\x16.google.protobuf.EmptyH\x00R\x04infoB\x07\n\x05value\"e\n\x03Log\x12\x44\n\x05level\x18\x01 \x01(\x0b\x32..elimity.insights.customgateway.v1alpha1.LevelR\x05level\x12\x18\n\x07message\x18\x02 \x01(\tR\x07message\"\xcc\x01\n\x14PerformImportRequest\x12\x61\n\x06\x66ields\x18\x01 \x03(\x0b\x32I.elimity.insights.customgateway.v1alpha1.PerformImportRequest.FieldsEntryR\x06\x66ields\x1aQ\n\x0b\x46ieldsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.ValueR\x05value:\x02\x38\x01\"\xfc\x01\n\x15PerformImportResponse\x12\x42\n\x06\x65ntity\x18\x01 \x01(\x0b\x32(.elimity.insights.common.v1alpha1.EntityH\x00R\x06\x65ntity\x12@\n\x03log\x18\x02 \x01(\x0b\x32,.elimity.insights.customgateway.v1alpha1.LogH\x00R\x03log\x12T\n\x0crelationship\x18\x03 \x01(\x0b\x32..elimity.insights.common.v1alpha1.RelationshipH\x00R\x0crelationshipB\x07\n\x05value2\x9c\x01\n\x07Service\x12\x90\x01\n\rPerformImport\x12=.elimity.insights.customgateway.v1alpha1.PerformImportRequest\x1a>.elimity.insights.customgateway.v1alpha1.PerformImportResponse0\x01\x42QZOgithub.com/elimity-com/insights-sdk/gen/elimity/insights/customgateway/v1alpha1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'elimity.insights.customgateway.v1alpha1.customgateway_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'ZOgithub.com/elimity-com/insights-sdk/gen/elimity/insights/customgateway/v1alpha1' + _globals['_PERFORMIMPORTREQUEST_FIELDSENTRY']._loaded_options = None + _globals['_PERFORMIMPORTREQUEST_FIELDSENTRY']._serialized_options = b'8\001' + _globals['_LEVEL']._serialized_start=210 + _globals['_LEVEL']._serialized_end=320 + _globals['_LOG']._serialized_start=322 + _globals['_LOG']._serialized_end=423 + _globals['_PERFORMIMPORTREQUEST']._serialized_start=426 + _globals['_PERFORMIMPORTREQUEST']._serialized_end=630 + _globals['_PERFORMIMPORTREQUEST_FIELDSENTRY']._serialized_start=549 + _globals['_PERFORMIMPORTREQUEST_FIELDSENTRY']._serialized_end=630 + _globals['_PERFORMIMPORTRESPONSE']._serialized_start=633 + _globals['_PERFORMIMPORTRESPONSE']._serialized_end=885 + _globals['_SERVICE']._serialized_start=888 + _globals['_SERVICE']._serialized_end=1044 +# @@protoc_insertion_point(module_scope) diff --git a/gen/elimity/insights/customgateway/v1alpha1/customgateway_pb2.pyi b/gen/elimity/insights/customgateway/v1alpha1/customgateway_pb2.pyi new file mode 100644 index 0000000..d225b0d --- /dev/null +++ b/gen/elimity/insights/customgateway/v1alpha1/customgateway_pb2.pyi @@ -0,0 +1,48 @@ +from elimity.insights.common.v1alpha1 import common_pb2 as _common_pb2 +from google.protobuf import empty_pb2 as _empty_pb2 +from google.protobuf import struct_pb2 as _struct_pb2 +from google.protobuf.internal import containers as _containers +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union + +DESCRIPTOR: _descriptor.FileDescriptor + +class Level(_message.Message): + __slots__ = ("alert", "info") + ALERT_FIELD_NUMBER: _ClassVar[int] + INFO_FIELD_NUMBER: _ClassVar[int] + alert: _empty_pb2.Empty + info: _empty_pb2.Empty + def __init__(self, alert: _Optional[_Union[_empty_pb2.Empty, _Mapping]] = ..., info: _Optional[_Union[_empty_pb2.Empty, _Mapping]] = ...) -> None: ... + +class Log(_message.Message): + __slots__ = ("level", "message") + LEVEL_FIELD_NUMBER: _ClassVar[int] + MESSAGE_FIELD_NUMBER: _ClassVar[int] + level: Level + message: str + def __init__(self, level: _Optional[_Union[Level, _Mapping]] = ..., message: _Optional[str] = ...) -> None: ... + +class PerformImportRequest(_message.Message): + __slots__ = ("fields",) + class FieldsEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: _struct_pb2.Value + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[_struct_pb2.Value, _Mapping]] = ...) -> None: ... + FIELDS_FIELD_NUMBER: _ClassVar[int] + fields: _containers.MessageMap[str, _struct_pb2.Value] + def __init__(self, fields: _Optional[_Mapping[str, _struct_pb2.Value]] = ...) -> None: ... + +class PerformImportResponse(_message.Message): + __slots__ = ("entity", "log", "relationship") + ENTITY_FIELD_NUMBER: _ClassVar[int] + LOG_FIELD_NUMBER: _ClassVar[int] + RELATIONSHIP_FIELD_NUMBER: _ClassVar[int] + entity: _common_pb2.Entity + log: Log + relationship: _common_pb2.Relationship + def __init__(self, entity: _Optional[_Union[_common_pb2.Entity, _Mapping]] = ..., log: _Optional[_Union[Log, _Mapping]] = ..., relationship: _Optional[_Union[_common_pb2.Relationship, _Mapping]] = ...) -> None: ... diff --git a/gen/elimity/insights/customgateway/v1alpha1/v1alpha1connect/__init__.py b/gen/elimity/insights/customgateway/v1alpha1/v1alpha1connect/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/customgateway/v1alpha1/v1alpha1connect/__init__.pyi b/gen/elimity/insights/customgateway/v1alpha1/v1alpha1connect/__init__.pyi new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/export/__init__.py b/gen/elimity/insights/export/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/export/__init__.pyi b/gen/elimity/insights/export/__init__.pyi new file mode 100644 index 0000000..374b089 --- /dev/null +++ b/gen/elimity/insights/export/__init__.pyi @@ -0,0 +1 @@ +from . import v1alpha1 diff --git a/gen/elimity/insights/export/v1alpha1/__init__.py b/gen/elimity/insights/export/v1alpha1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/export/v1alpha1/__init__.pyi b/gen/elimity/insights/export/v1alpha1/__init__.pyi new file mode 100644 index 0000000..377d108 --- /dev/null +++ b/gen/elimity/insights/export/v1alpha1/__init__.pyi @@ -0,0 +1,2 @@ +from . import export_pb2 +from . import v1alpha1connect diff --git a/gen/elimity/insights/export/v1alpha1/export_connect.py b/gen/elimity/insights/export/v1alpha1/export_connect.py new file mode 100644 index 0000000..ca77df2 --- /dev/null +++ b/gen/elimity/insights/export/v1alpha1/export_connect.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +# Generated by https://github.com/connectrpc/connect-python. DO NOT EDIT! +# source: elimity/insights/export/v1alpha1/export.proto + +from collections.abc import AsyncIterator, Iterable, Iterator, Mapping +from typing import Protocol + +from connectrpc.client import ConnectClient, ConnectClientSync +from connectrpc.code import Code +from connectrpc.errors import ConnectError +from connectrpc.interceptor import Interceptor, InterceptorSync +from connectrpc.method import IdempotencyLevel, MethodInfo +from connectrpc.request import Headers, RequestContext +from connectrpc.server import ConnectASGIApplication, ConnectWSGIApplication, Endpoint, EndpointSync +import elimity.insights.export.v1alpha1.export_pb2 as elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2 + + +class Service(Protocol): + def export(self, request: elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, ctx: RequestContext) -> AsyncIterator[elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse]: + raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") + + +class ServiceASGIApplication(ConnectASGIApplication): + def __init__(self, service: Service, *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None) -> None: + super().__init__( + endpoints={ + "/elimity.insights.export.v1alpha1.Service/Export": Endpoint.server_stream( + method=MethodInfo( + name="Export", + service_name="elimity.insights.export.v1alpha1.Service", + input=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, + output=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + function=service.export, + ), + }, + interceptors=interceptors, + read_max_bytes=read_max_bytes, + ) + + @property + def path(self) -> str: + """Returns the URL path to mount the application to when serving multiple applications.""" + return "/elimity.insights.export.v1alpha1.Service" + + +class ServiceClient(ConnectClient): + def export( + self, + request: elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, + *, + headers: Headers | Mapping[str, str] | None = None, + timeout_ms: int | None = None, + ) -> AsyncIterator[elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse]: + return self.execute_server_stream( + request=request, + method=MethodInfo( + name="Export", + service_name="elimity.insights.export.v1alpha1.Service", + input=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, + output=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + headers=headers, + timeout_ms=timeout_ms, + ) + + +class ServiceSync(Protocol): + def export(self, request: elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, ctx: RequestContext) -> Iterator[elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse]: + raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") + + +class ServiceWSGIApplication(ConnectWSGIApplication): + def __init__(self, service: ServiceSync, interceptors: Iterable[InterceptorSync]=(), read_max_bytes: int | None = None) -> None: + super().__init__( + endpoints={ + "/elimity.insights.export.v1alpha1.Service/Export": EndpointSync.server_stream( + method=MethodInfo( + name="Export", + service_name="elimity.insights.export.v1alpha1.Service", + input=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, + output=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + function=service.export, + ), + }, + interceptors=interceptors, + read_max_bytes=read_max_bytes, + ) + + @property + def path(self) -> str: + """Returns the URL path to mount the application to when serving multiple applications.""" + return "/elimity.insights.export.v1alpha1.Service" + + +class ServiceClientSync(ConnectClientSync): + def export( + self, + request: elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, + *, + headers: Headers | Mapping[str, str] | None = None, + timeout_ms: int | None = None, + ) -> Iterator[elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse]: + return self.execute_server_stream( + request=request, + method=MethodInfo( + name="Export", + service_name="elimity.insights.export.v1alpha1.Service", + input=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportRequest, + output=elimity_dot_insights_dot_export_dot_v1alpha1_dot_export__pb2.ExportResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + headers=headers, + timeout_ms=timeout_ms, + ) diff --git a/gen/elimity/insights/export/v1alpha1/export_pb2.py b/gen/elimity/insights/export/v1alpha1/export_pb2.py new file mode 100644 index 0000000..74110ac --- /dev/null +++ b/gen/elimity/insights/export/v1alpha1/export_pb2.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: elimity/insights/export/v1alpha1/export.proto +# Protobuf Python Version: 5.29.5 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 29, + 5, + '', + 'elimity/insights/export/v1alpha1/export.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from elimity.insights.common.v1alpha1 import common_pb2 as elimity_dot_insights_dot_common_dot_v1alpha1_dot_common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n-elimity/insights/export/v1alpha1/export.proto\x12 elimity.insights.export.v1alpha1\x1a-elimity/insights/common/v1alpha1/common.proto\"\x9f\x01\n\rExportRequest\x12 \n\x0c\x61pi_token_id\x18\x01 \x01(\x03R\napiTokenId\x12(\n\x10\x61pi_token_secret\x18\x02 \x01(\x0cR\x0e\x61piTokenSecret\x12\x42\n\x07targets\x18\x03 \x03(\x0b\x32(.elimity.insights.export.v1alpha1.TargetR\x07targets\"o\n\x0e\x45xportResponse\x12:\n\x04item\x18\x01 \x01(\x0b\x32&.elimity.insights.export.v1alpha1.ItemR\x04item\x12!\n\x0ctarget_index\x18\x02 \x01(\x03R\x0btargetIndex\"\x97\x01\n\x06\x46ilter\x12!\n\x0b\x65ntity_type\x18\x01 \x01(\tH\x00R\nentityType\x12\x61\n\x11relationship_type\x18\x02 \x01(\x0b\x32\x32.elimity.insights.export.v1alpha1.RelationshipTypeH\x00R\x10relationshipTypeB\x07\n\x05value\"\xa9\x01\n\x04Item\x12\x42\n\x06\x65ntity\x18\x01 \x01(\x0b\x32(.elimity.insights.common.v1alpha1.EntityH\x00R\x06\x65ntity\x12T\n\x0crelationship\x18\x02 \x01(\x0b\x32..elimity.insights.common.v1alpha1.RelationshipH\x00R\x0crelationshipB\x07\n\x05value\"b\n\x10RelationshipType\x12(\n\x10\x66rom_entity_type\x18\x01 \x01(\tR\x0e\x66romEntityType\x12$\n\x0eto_entity_type\x18\x02 \x01(\tR\x0ctoEntityType\"g\n\x06Target\x12@\n\x06\x66ilter\x18\x01 \x01(\x0b\x32(.elimity.insights.export.v1alpha1.FilterR\x06\x66ilter\x12\x1b\n\tsource_id\x18\x02 \x01(\x03R\x08sourceId2x\n\x07Service\x12m\n\x06\x45xport\x12/.elimity.insights.export.v1alpha1.ExportRequest\x1a\x30.elimity.insights.export.v1alpha1.ExportResponse0\x01\x42JZHgithub.com/elimity-com/insights-sdk/gen/elimity/insights/export/v1alpha1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'elimity.insights.export.v1alpha1.export_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'ZHgithub.com/elimity-com/insights-sdk/gen/elimity/insights/export/v1alpha1' + _globals['_EXPORTREQUEST']._serialized_start=131 + _globals['_EXPORTREQUEST']._serialized_end=290 + _globals['_EXPORTRESPONSE']._serialized_start=292 + _globals['_EXPORTRESPONSE']._serialized_end=403 + _globals['_FILTER']._serialized_start=406 + _globals['_FILTER']._serialized_end=557 + _globals['_ITEM']._serialized_start=560 + _globals['_ITEM']._serialized_end=729 + _globals['_RELATIONSHIPTYPE']._serialized_start=731 + _globals['_RELATIONSHIPTYPE']._serialized_end=829 + _globals['_TARGET']._serialized_start=831 + _globals['_TARGET']._serialized_end=934 + _globals['_SERVICE']._serialized_start=936 + _globals['_SERVICE']._serialized_end=1056 +# @@protoc_insertion_point(module_scope) diff --git a/gen/elimity/insights/export/v1alpha1/export_pb2.pyi b/gen/elimity/insights/export/v1alpha1/export_pb2.pyi new file mode 100644 index 0000000..b18e5c6 --- /dev/null +++ b/gen/elimity/insights/export/v1alpha1/export_pb2.pyi @@ -0,0 +1,57 @@ +from elimity.insights.common.v1alpha1 import common_pb2 as _common_pb2 +from google.protobuf.internal import containers as _containers +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union + +DESCRIPTOR: _descriptor.FileDescriptor + +class ExportRequest(_message.Message): + __slots__ = ("api_token_id", "api_token_secret", "targets") + API_TOKEN_ID_FIELD_NUMBER: _ClassVar[int] + API_TOKEN_SECRET_FIELD_NUMBER: _ClassVar[int] + TARGETS_FIELD_NUMBER: _ClassVar[int] + api_token_id: int + api_token_secret: bytes + targets: _containers.RepeatedCompositeFieldContainer[Target] + def __init__(self, api_token_id: _Optional[int] = ..., api_token_secret: _Optional[bytes] = ..., targets: _Optional[_Iterable[_Union[Target, _Mapping]]] = ...) -> None: ... + +class ExportResponse(_message.Message): + __slots__ = ("item", "target_index") + ITEM_FIELD_NUMBER: _ClassVar[int] + TARGET_INDEX_FIELD_NUMBER: _ClassVar[int] + item: Item + target_index: int + def __init__(self, item: _Optional[_Union[Item, _Mapping]] = ..., target_index: _Optional[int] = ...) -> None: ... + +class Filter(_message.Message): + __slots__ = ("entity_type", "relationship_type") + ENTITY_TYPE_FIELD_NUMBER: _ClassVar[int] + RELATIONSHIP_TYPE_FIELD_NUMBER: _ClassVar[int] + entity_type: str + relationship_type: RelationshipType + def __init__(self, entity_type: _Optional[str] = ..., relationship_type: _Optional[_Union[RelationshipType, _Mapping]] = ...) -> None: ... + +class Item(_message.Message): + __slots__ = ("entity", "relationship") + ENTITY_FIELD_NUMBER: _ClassVar[int] + RELATIONSHIP_FIELD_NUMBER: _ClassVar[int] + entity: _common_pb2.Entity + relationship: _common_pb2.Relationship + def __init__(self, entity: _Optional[_Union[_common_pb2.Entity, _Mapping]] = ..., relationship: _Optional[_Union[_common_pb2.Relationship, _Mapping]] = ...) -> None: ... + +class RelationshipType(_message.Message): + __slots__ = ("from_entity_type", "to_entity_type") + FROM_ENTITY_TYPE_FIELD_NUMBER: _ClassVar[int] + TO_ENTITY_TYPE_FIELD_NUMBER: _ClassVar[int] + from_entity_type: str + to_entity_type: str + def __init__(self, from_entity_type: _Optional[str] = ..., to_entity_type: _Optional[str] = ...) -> None: ... + +class Target(_message.Message): + __slots__ = ("filter", "source_id") + FILTER_FIELD_NUMBER: _ClassVar[int] + SOURCE_ID_FIELD_NUMBER: _ClassVar[int] + filter: Filter + source_id: int + def __init__(self, filter: _Optional[_Union[Filter, _Mapping]] = ..., source_id: _Optional[int] = ...) -> None: ... diff --git a/gen/elimity/insights/export/v1alpha1/v1alpha1connect/__init__.py b/gen/elimity/insights/export/v1alpha1/v1alpha1connect/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/insights/export/v1alpha1/v1alpha1connect/__init__.pyi b/gen/elimity/insights/export/v1alpha1/v1alpha1connect/__init__.pyi new file mode 100644 index 0000000..e69de29 diff --git a/gen/elimity/py.typed b/gen/elimity/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..8215b0e --- /dev/null +++ b/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +disallow_any_explicit = True +strict = True diff --git a/package-lock.json b/package-lock.json index 004b908..616b5c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@bufbuild/buf": "^1.51.0", "@types/express": "^5.0.3", "@types/lodash": "^4.17.20", "@types/node": "^22.15.33", @@ -24,150 +23,6 @@ "prettier": "^3.5.3" } }, - "node_modules/@bufbuild/buf": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.51.0.tgz", - "integrity": "sha512-DjN9wA1g9q1lYzuDLiC1v9db35mzpHEdG8iM7D36RjWdIByhIgmh/O5hoYSfFL7kMD95p3vGTPz/ZKsClf15VA==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "bin": { - "buf": "bin/buf", - "protoc-gen-buf-breaking": "bin/protoc-gen-buf-breaking", - "protoc-gen-buf-lint": "bin/protoc-gen-buf-lint" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@bufbuild/buf-darwin-arm64": "1.51.0", - "@bufbuild/buf-darwin-x64": "1.51.0", - "@bufbuild/buf-linux-aarch64": "1.51.0", - "@bufbuild/buf-linux-armv7": "1.51.0", - "@bufbuild/buf-linux-x64": "1.51.0", - "@bufbuild/buf-win32-arm64": "1.51.0", - "@bufbuild/buf-win32-x64": "1.51.0" - } - }, - "node_modules/@bufbuild/buf-darwin-arm64": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.51.0.tgz", - "integrity": "sha512-VIXNyIuCY9JxEcJ+oZimY8qiyjCglB6qmUf5yLLxKVhq8wGGA+rFn7iqXz7ig1sNV0KAEhHFAyfGtncjcJULRA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@bufbuild/buf-darwin-x64": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.51.0.tgz", - "integrity": "sha512-0d3j+Lpf4PFFS7RGkvMIJdeJ+HeSPgu0EPcMfbmOrNEM2c2/NSWqLPxYv6iMlL4Fl2wp4U3mSMls5IeXFf56lw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@bufbuild/buf-linux-aarch64": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.51.0.tgz", - "integrity": "sha512-eFTvxI6B1snQii9vdb66DnP5Wylvy+vE6lq/DMnI2qCOQoZ1OsVZ9hm91b4r5Rcg2gEEJIXe3ExCJtRnYChCTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@bufbuild/buf-linux-armv7": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-armv7/-/buf-linux-armv7-1.51.0.tgz", - "integrity": "sha512-mnWmMW1V3GId9BSUbgRKPn5UZTrtVP2hXhuvPMKGRvIt5CqgQUXNJbwUQMa9j1zMQLEIViVa6yGSeewGjNahIw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@bufbuild/buf-linux-x64": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.51.0.tgz", - "integrity": "sha512-CiiFFPgQs3nDlAqr0CnbYBw2uKodBPJCaIrK/EPFqkJdWD58zcGbbtZp5uk3+uHHZ/syBxI8zl/iQSoeypt9cQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@bufbuild/buf-win32-arm64": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.51.0.tgz", - "integrity": "sha512-9J9WckymQRw+iJ9cg8JquYwlSLYDfilx8vmzsoq0LQdt9yjR6WAq0cHjKuZERSZ2q+beMdi8N9Z0vvfkL1GzGA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@bufbuild/buf-win32-x64": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.51.0.tgz", - "integrity": "sha512-adskoC+2pr2GzuQNeFv8qe6uj+fndqIubN7smXwCvL8SFBEk8Eic8VSeqfser6cQG64SfTKQPuRW3iqikngWHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@bufbuild/protobuf": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.1.tgz", diff --git a/package.json b/package.json index 2ea55e8..67b6d1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,5 @@ { "devDependencies": { - "@bufbuild/buf": "^1.51.0", "@types/express": "^5.0.3", "@types/lodash": "^4.17.20", "@types/node": "^22.15.33", diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..ddc7c50 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,489 @@ +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. + +[[package]] +name = "anyio" +version = "4.11.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, + {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.31.0)"] + +[[package]] +name = "black" +version = "25.9.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "black-25.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ce41ed2614b706fd55fd0b4a6909d06b5bab344ffbfadc6ef34ae50adba3d4f7"}, + {file = "black-25.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ab0ce111ef026790e9b13bd216fa7bc48edd934ffc4cbf78808b235793cbc92"}, + {file = "black-25.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f96b6726d690c96c60ba682955199f8c39abc1ae0c3a494a9c62c0184049a713"}, + {file = "black-25.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:d119957b37cc641596063cd7db2656c5be3752ac17877017b2ffcdb9dfc4d2b1"}, + {file = "black-25.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:456386fe87bad41b806d53c062e2974615825c7a52159cde7ccaeb0695fa28fa"}, + {file = "black-25.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a16b14a44c1af60a210d8da28e108e13e75a284bf21a9afa6b4571f96ab8bb9d"}, + {file = "black-25.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aaf319612536d502fdd0e88ce52d8f1352b2c0a955cc2798f79eeca9d3af0608"}, + {file = "black-25.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:c0372a93e16b3954208417bfe448e09b0de5cc721d521866cd9e0acac3c04a1f"}, + {file = "black-25.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1b9dc70c21ef8b43248f1d86aedd2aaf75ae110b958a7909ad8463c4aa0880b0"}, + {file = "black-25.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e46eecf65a095fa62e53245ae2795c90bdecabd53b50c448d0a8bcd0d2e74c4"}, + {file = "black-25.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9101ee58ddc2442199a25cb648d46ba22cd580b00ca4b44234a324e3ec7a0f7e"}, + {file = "black-25.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:77e7060a00c5ec4b3367c55f39cf9b06e68965a4f2e61cecacd6d0d9b7ec945a"}, + {file = "black-25.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0172a012f725b792c358d57fe7b6b6e8e67375dd157f64fa7a3097b3ed3e2175"}, + {file = "black-25.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3bec74ee60f8dfef564b573a96b8930f7b6a538e846123d5ad77ba14a8d7a64f"}, + {file = "black-25.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b756fc75871cb1bcac5499552d771822fd9db5a2bb8db2a7247936ca48f39831"}, + {file = "black-25.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:846d58e3ce7879ec1ffe816bb9df6d006cd9590515ed5d17db14e17666b2b357"}, + {file = "black-25.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ef69351df3c84485a8beb6f7b8f9721e2009e20ef80a8d619e2d1788b7816d47"}, + {file = "black-25.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e3c1f4cd5e93842774d9ee4ef6cd8d17790e65f44f7cdbaab5f2cf8ccf22a823"}, + {file = "black-25.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:154b06d618233fe468236ba1f0e40823d4eb08b26f5e9261526fde34916b9140"}, + {file = "black-25.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:e593466de7b998374ea2585a471ba90553283fb9beefcfa430d84a2651ed5933"}, + {file = "black-25.9.0-py3-none-any.whl", hash = "sha256:474b34c1342cdc157d307b56c4c65bce916480c4a8f6551fdc6bf9b486a7c4ae"}, + {file = "black-25.9.0.tar.gz", hash = "sha256:0474bca9a0dd1b51791fcc507a4e02078a1c63f6d4e4ae5544b9848c7adfb619"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +pytokens = ">=0.1.10" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2025.10.5" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de"}, + {file = "certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43"}, +] + +[[package]] +name = "click" +version = "8.3.0" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"}, + {file = "click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "connect-python" +version = "0.5.0" +description = "Server and client runtime library for Connect RPC" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "connect_python-0.5.0-py3-none-any.whl", hash = "sha256:71caab21ca3a5458510fbd4e5439c75399bf109498983f05454f0f8160e70fd5"}, + {file = "connect_python-0.5.0.tar.gz", hash = "sha256:8d761e8f2fd14dc7854adbb02f2e0a6f22b120db378f3486e55a6e984427d380"}, +] + +[package.dependencies] +httpx = "*" +protobuf = ">=5.28" + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version == \"3.10\"" +files = [ + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.16" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "isort" +version = "6.1.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "isort-6.1.0-py3-none-any.whl", hash = "sha256:58d8927ecce74e5087aef019f778d4081a3b6c98f15a80ba35782ca8a2097784"}, + {file = "isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481"}, +] + +[package.extras] +colors = ["colorama"] +plugins = ["setuptools"] + +[[package]] +name = "mypy" +version = "1.18.2" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"}, + {file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"}, + {file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"}, + {file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"}, + {file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"}, + {file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"}, + {file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"}, + {file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"}, + {file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"}, + {file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"}, + {file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"}, + {file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"}, + {file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"}, + {file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"}, + {file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"}, + {file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"}, +] + +[package.dependencies] +mypy_extensions = ">=1.0.0" +pathspec = ">=0.9.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing_extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.4.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85"}, + {file = "platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + +[[package]] +name = "protobuf" +version = "5.29.5" +description = "" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079"}, + {file = "protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc"}, + {file = "protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671"}, + {file = "protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015"}, + {file = "protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61"}, + {file = "protobuf-5.29.5-cp38-cp38-win32.whl", hash = "sha256:ef91363ad4faba7b25d844ef1ada59ff1604184c0bcd8b39b8a6bef15e1af238"}, + {file = "protobuf-5.29.5-cp38-cp38-win_amd64.whl", hash = "sha256:7318608d56b6402d2ea7704ff1e1e4597bee46d760e7e4dd42a3d45e24b87f2e"}, + {file = "protobuf-5.29.5-cp39-cp39-win32.whl", hash = "sha256:6f642dc9a61782fa72b90878af134c5afe1917c89a568cd3476d758d3c3a0736"}, + {file = "protobuf-5.29.5-cp39-cp39-win_amd64.whl", hash = "sha256:470f3af547ef17847a28e1f47200a1cbf0ba3ff57b7de50d22776607cd2ea353"}, + {file = "protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5"}, + {file = "protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84"}, +] + +[[package]] +name = "protoletariat" +version = "3.3.10" +description = "Python protocol buffers for the rest of us" +optional = false +python-versions = "<4.0,>=3.8" +groups = ["dev"] +files = [ + {file = "protoletariat-3.3.10-py3-none-any.whl", hash = "sha256:4b0ab790a1791613d9ef1c4159e03424a7f056592ca66578ba585ae96686ee2d"}, + {file = "protoletariat-3.3.10.tar.gz", hash = "sha256:bfa0e663fe4c9e3584101779b8b9f5a77b8af623aa25f680e0559b7d2609039b"}, +] + +[package.dependencies] +click = ">=8,<9" +protobuf = ">=3.19.1,<6" + +[package.extras] +grpcio-tools = ["grpcio-tools (>=1.42.0,<2)"] + +[[package]] +name = "pytokens" +version = "0.1.10" +description = "A Fast, spec compliant Python 3.12+ tokenizer that runs on older Pythons." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytokens-0.1.10-py3-none-any.whl", hash = "sha256:db7b72284e480e69fb085d9f251f66b3d2df8b7166059261258ff35f50fb711b"}, + {file = "pytokens-0.1.10.tar.gz", hash = "sha256:c9a4bfa0be1d26aebce03e6884ba454e842f186a59ea43a6d3b25af58223c044"}, +] + +[package.extras] +dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "twine", "wheel"] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version == \"3.10\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "types-protobuf" +version = "5.29.1.20250403" +description = "Typing stubs for protobuf" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "types_protobuf-5.29.1.20250403-py3-none-any.whl", hash = "sha256:c71de04106a2d54e5b2173d0a422058fae0ef2d058d70cf369fb797bf61ffa59"}, + {file = "types_protobuf-5.29.1.20250403.tar.gz", hash = "sha256:7ff44f15022119c9d7558ce16e78b2d485bf7040b4fadced4dd069bb5faf77a2"}, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] +markers = {main = "python_version < \"3.13\""} + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10,<4" +content-hash = "ace62194e58d7261bfd2bc1b1d89b0466404c38187b8bdabd5af409bc714485f" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4dd0b79 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[build-system] +build-backend = "poetry.core.masonry.api" +requires = ["poetry-core>=1.0.0"] + +[dependency-groups] +dev = [ + "protoletariat (>=3.3.10,<4)", + "mypy (>=1.18.2,<2)", + "types-protobuf (>=5.29.1.20250403,<6)", + "black (>=25.9.0,<26.0.0)", + "isort (>=6.0.1,<7.0.0)" +] + +[project] +dependencies = [ + "connect-python (>=0.5.0,<0.6)", +] +requires-python = ">=3.10,<4" +name = "elimity-insights-sdk" +version = "1.0.0a0" + +[tool.poetry] +packages = [ + { from = "gen", include = "elimity" }, + { from = "src", include = "elimity_insights_sdk" } +] diff --git a/src/elimity_insights_sdk/__init__.py b/src/elimity_insights_sdk/__init__.py new file mode 100644 index 0000000..d108503 --- /dev/null +++ b/src/elimity_insights_sdk/__init__.py @@ -0,0 +1,31 @@ +from elimity_insights_sdk._sdk import ( + BooleanValue, + DateTimeValue, + DateValue, + EntityItem, + Item, + Level, + LogItem, + NumberValue, + RelationshipItem, + StringValue, + TimeValue, + Value, + app, +) + +__all__ = [ + "BooleanValue", + "DateValue", + "DateTimeValue", + "EntityItem", + "Item", + "Level", + "LogItem", + "NumberValue", + "RelationshipItem", + "StringValue", + "TimeValue", + "Value", + "app", +] diff --git a/src/elimity_insights_sdk/_sdk.py b/src/elimity_insights_sdk/_sdk.py new file mode 100644 index 0000000..61d6d76 --- /dev/null +++ b/src/elimity_insights_sdk/_sdk.py @@ -0,0 +1,190 @@ +from collections.abc import AsyncIterator, Callable +from dataclasses import dataclass +from datetime import date, datetime, time +from enum import Enum, auto +from typing import Union + +from connectrpc.request import RequestContext +from elimity.insights.common.v1alpha1.common_pb2 import Entity, Relationship +from elimity.insights.common.v1alpha1.common_pb2 import Value as CommonValue +from elimity.insights.customgateway.v1alpha1.customgateway_connect import ( + ServiceASGIApplication, +) +from elimity.insights.customgateway.v1alpha1.customgateway_pb2 import ( + Level as GatewayLevel, +) +from elimity.insights.customgateway.v1alpha1.customgateway_pb2 import ( + Log, + PerformImportRequest, + PerformImportResponse, +) +from google.protobuf.empty_pb2 import Empty +from google.protobuf.json_format import MessageToDict +from google.protobuf.timestamp_pb2 import Timestamp + + +@dataclass +class BooleanValue: + value: bool + + +@dataclass +class DateTimeValue: + value: datetime + + +@dataclass +class DateValue: + value: date + + +@dataclass +class EntityItem: + attribute_assignments: dict[str, "Value"] + id: str + name: str + type: str + + +@dataclass +class LogItem: + level: "Level" + message: str + + +@dataclass +class RelationshipItem: + attribute_assignments: dict[str, "Value"] + from_entity_id: str + from_entity_type: str + to_entity_id: str + to_entity_type: str + + +Item = Union[EntityItem, LogItem, RelationshipItem] + + +class Level(Enum): + ALERT = auto() + INFO = auto() + + +@dataclass +class NumberValue: + value: float + + +@dataclass +class StringValue: + value: str + + +@dataclass +class TimeValue: + value: time + + +Value = Union[ + BooleanValue, DateValue, DateTimeValue, NumberValue, StringValue, TimeValue +] + + +def app( + fun: Callable[[dict[str, object]], AsyncIterator[Item]], +) -> ServiceASGIApplication: + service = _Service(fun) + return ServiceASGIApplication(service) + + +class _Service: + def __init__(self, fun: Callable[[dict[str, object]], AsyncIterator[Item]]): + self._fun = fun + + def perform_import( + self, req: PerformImportRequest, ctx: RequestContext[object, object] + ) -> AsyncIterator[PerformImportResponse]: + fields: dict[str, object] = {} + for key, value in req.fields.items(): + fields[key] = MessageToDict(value) + items = self._fun(fields) + return _generate_responses(items) + + +async def _generate_responses( + items: AsyncIterator[Item], +) -> AsyncIterator[PerformImportResponse]: + async for item in items: + yield _make_response(item) + + +def _make_assignments(assignments: dict[str, Value]) -> dict[str, CommonValue]: + ass: dict[str, CommonValue] = {} + for key, value in assignments.items(): + ass[key] = _make_value(value) + return ass + + +def _make_response(item: Item) -> PerformImportResponse: + if isinstance(item, EntityItem): + assignments = _make_assignments(item.attribute_assignments) + entity = Entity( + attribute_assignments=assignments, + id=item.id, + name=item.name, + type=item.type, + ) + return PerformImportResponse(entity=entity) + + if isinstance(item, LogItem): + empty = Empty() + level = ( + GatewayLevel(alert=empty) + if item.level is Level.ALERT + else GatewayLevel(info=empty) + ) + log = Log(level=level, message=item.message) + return PerformImportResponse(log=log) + + if isinstance(item, RelationshipItem): + assignments = _make_assignments(item.attribute_assignments) + relationship = Relationship( + attribute_assignments=assignments, + from_entity_id=item.from_entity_id, + from_entity_type=item.from_entity_type, + to_entity_id=item.to_entity_id, + to_entity_type=item.to_entity_type, + ) + return PerformImportResponse(relationship=relationship) + + +def _make_timestamp(datetime: datetime) -> Timestamp: + timestamp = Timestamp() + timestamp.FromDatetime(datetime) + return timestamp + + +def _make_value(value: Value) -> CommonValue: + if isinstance(value, BooleanValue): + return CommonValue(boolean=value.value) + + if isinstance(value, DateTimeValue): + timestamp = _make_timestamp(value.value) + return CommonValue(date_time=timestamp) + + if isinstance(value, DateValue): + date = value.value + dat = datetime(date.year, date.month, date.day) + timestamp = _make_timestamp(dat) + return CommonValue(date=timestamp) + + if isinstance(value, NumberValue): + return CommonValue(number=value.value) + + if isinstance(value, StringValue): + return CommonValue(string=value.value) + + if isinstance(value, TimeValue): + time = value.value + dat = datetime(1, 1, 1, time.hour, time.minute, time.second) + timestamp = _make_timestamp(dat) + return CommonValue(time=timestamp) diff --git a/src/elimity_insights_sdk/py.typed b/src/elimity_insights_sdk/py.typed new file mode 100644 index 0000000..e69de29