From e3afd60fbae31a5759292a73153cf4bde63ced86 Mon Sep 17 00:00:00 2001 From: Andrey Kataev Date: Tue, 14 Oct 2025 18:57:17 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=BD=D0=B0=20justfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 4 +- Makefile | 93 ------------ justfile | 37 +++++ pyproject.toml | 16 +- .../clients/base_client.py | 4 +- .../clients/client_factory.py | 6 +- .../clients/comment.py | 7 +- src/{gateway => apigateway}/clients/mod.py | 7 +- src/{gateway => apigateway}/clients/rating.py | 7 +- .../converters/mod_status_converter.py | 2 +- .../esclient_graphql.py | 2 +- .../helpers/id_helper.py | 0 src/{gateway => apigateway}/helpers/retry.py | 0 .../resolvers/grpc_error_wrapper.py | 0 .../resolvers/mutation/comment.py | 2 +- .../resolvers/mutation/mod.py | 2 +- .../resolvers/mutation/rating.py | 2 +- .../resolvers/mutation/root.py | 0 .../resolvers/query/comment.py | 2 +- .../resolvers/query/mod.py | 4 +- .../resolvers/query/root.py | 0 .../schema/mutation/comment.graphql | 0 .../schema/mutation/mod.graphql | 0 .../schema/mutation/rating.graphql | 0 .../schema/query/comment.graphql | 0 .../schema/query/mod.graphql | 0 .../schema/schema.graphql | 0 src/{gateway => apigateway}/server.py | 18 +-- src/{gateway => apigateway}/settings.py | 0 .../stubs/comment}/comment_pb2.py | 0 .../stubs/comment}/comment_pb2.pyi | 0 .../stubs/comment}/comment_pb2_grpc.py | 2 +- src/apigateway/stubs/mod/__init__.py | 0 .../stubs => apigateway/stubs/mod}/mod_pb2.py | 0 .../stubs/mod}/mod_pb2.pyi | 0 .../stubs/mod}/mod_pb2_grpc.py | 2 +- src/apigateway/stubs/rating/__init__.py | 0 .../stubs/rating}/rating_pb2.py | 0 .../stubs/rating}/rating_pb2.pyi | 0 .../stubs/rating}/rating_pb2_grpc.py | 2 +- src/apigateway/stubs/user/__init__.py | 0 src/apigateway/stubs/user/user_pb2.py | 45 ++++++ src/apigateway/stubs/user/user_pb2.pyi | 37 +++++ src/apigateway/stubs/user/user_pb2_grpc.py | 140 ++++++++++++++++++ tools/common.just | 44 ++++++ load_envs.sh => tools/load_envs.sh | 5 +- 46 files changed, 346 insertions(+), 146 deletions(-) delete mode 100644 Makefile create mode 100644 justfile rename src/{gateway => apigateway}/clients/base_client.py (97%) rename src/{gateway => apigateway}/clients/client_factory.py (89%) rename src/{gateway => apigateway}/clients/comment.py (90%) rename src/{gateway => apigateway}/clients/mod.py (90%) rename src/{gateway => apigateway}/clients/rating.py (83%) rename src/{gateway => apigateway}/converters/mod_status_converter.py (93%) rename src/{gateway => apigateway}/esclient_graphql.py (82%) rename src/{gateway => apigateway}/helpers/id_helper.py (100%) rename src/{gateway => apigateway}/helpers/retry.py (100%) rename src/{gateway => apigateway}/resolvers/grpc_error_wrapper.py (100%) rename src/{gateway => apigateway}/resolvers/mutation/comment.py (97%) rename src/{gateway => apigateway}/resolvers/mutation/mod.py (96%) rename src/{gateway => apigateway}/resolvers/mutation/rating.py (94%) rename src/{gateway => apigateway}/resolvers/mutation/root.py (100%) rename src/{gateway => apigateway}/resolvers/query/comment.py (95%) rename src/{gateway => apigateway}/resolvers/query/mod.py (90%) rename src/{gateway => apigateway}/resolvers/query/root.py (100%) rename src/{gateway => apigateway}/schema/mutation/comment.graphql (100%) rename src/{gateway => apigateway}/schema/mutation/mod.graphql (100%) rename src/{gateway => apigateway}/schema/mutation/rating.graphql (100%) rename src/{gateway => apigateway}/schema/query/comment.graphql (100%) rename src/{gateway => apigateway}/schema/query/mod.graphql (100%) rename src/{gateway => apigateway}/schema/schema.graphql (100%) rename src/{gateway => apigateway}/server.py (78%) rename src/{gateway => apigateway}/settings.py (100%) rename src/{gateway/stubs => apigateway/stubs/comment}/comment_pb2.py (100%) rename src/{gateway/stubs => apigateway/stubs/comment}/comment_pb2.pyi (100%) rename src/{gateway/stubs => apigateway/stubs/comment}/comment_pb2_grpc.py (99%) create mode 100644 src/apigateway/stubs/mod/__init__.py rename src/{gateway/stubs => apigateway/stubs/mod}/mod_pb2.py (100%) rename src/{gateway/stubs => apigateway/stubs/mod}/mod_pb2.pyi (100%) rename src/{gateway/stubs => apigateway/stubs/mod}/mod_pb2_grpc.py (99%) create mode 100644 src/apigateway/stubs/rating/__init__.py rename src/{gateway/stubs => apigateway/stubs/rating}/rating_pb2.py (100%) rename src/{gateway/stubs => apigateway/stubs/rating}/rating_pb2.pyi (100%) rename src/{gateway/stubs => apigateway/stubs/rating}/rating_pb2_grpc.py (98%) create mode 100644 src/apigateway/stubs/user/__init__.py create mode 100644 src/apigateway/stubs/user/user_pb2.py create mode 100644 src/apigateway/stubs/user/user_pb2.pyi create mode 100644 src/apigateway/stubs/user/user_pb2_grpc.py create mode 100644 tools/common.just rename load_envs.sh => tools/load_envs.sh (92%) diff --git a/Dockerfile b/Dockerfile index 1439043..acff1b5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,9 +16,9 @@ RUN pip install --no-cache-dir pdm && \ rm /tmp/req.txt COPY . . -RUN chmod +x load_envs.sh +RUN chmod +x tools/load_envs.sh ENV ENV=prod ENV PYTHONPATH=src -CMD ["./load_envs.sh", "python", "-u", "-m", "gateway.server"] +CMD ["./tools/load_envs.sh", "python", "-u", "-m", "apigateway.server"] diff --git a/Makefile b/Makefile deleted file mode 100644 index eb34645..0000000 --- a/Makefile +++ /dev/null @@ -1,93 +0,0 @@ --include .env - -COMMENT_PROTO_TAG ?= v0.0.8 -COMMENT_PROTO_NAME := comment.proto - -USER_PROTO_TAG ?= v0.0.8 -USER_PROTO_NAME := user.proto - -RATING_PROTO_TAG ?= v0.0.15 -RATING_PROTO_NAME := rating.proto - -MOD_PROTO_TAG ?= v0.1.2 -MOD_PROTO_NAME := mod.proto - -PROTO_REPO := https://raw.githubusercontent.com/esclient/protos - -TMP_DIR := .proto -OUT_DIR := stubs - -ifeq ($(OS),Windows_NT) -MKDIR = powershell -Command "New-Item -ItemType Directory -Force -Path" -RM = powershell -NoProfile -Command "Remove-Item -Path '$(TMP_DIR)' -Recurse -Force" -DOWN = powershell -Command "Invoke-WebRequest -Uri" -DOWN_OUT = -OutFile -FIX_IMPORTS = powershell -Command "& { \ - Get-ChildItem -Path '$(OUT_DIR)' -Filter '*_pb2_grpc.py' | \ - ForEach-Object { \ - (Get-Content $$_.FullName) -replace '^import (.*_pb2)', 'from . import $$1' | \ - Set-Content -Path $$_.FullName -Encoding UTF8 \ - } \ -}" -else -MKDIR = mkdir -p -RM = rm -rf $(TMP_DIR) -DOWN = wget -DOWN_OUT = -O -FIX_IMPORTS = \ - for f in $(OUT_DIR)/*_pb2_grpc.py; do \ - sed -i 's/^import \(.*_pb2\)/from . import \1/' $$f; \ - done -endif - -.PHONY: clean - -$(TMP_DIR) $(OUT_DIR): - $(MKDIR) "$@" - -$(TMP_DIR)/$(COMMENT_PROTO_NAME): | $(TMP_DIR) - $(DOWN) "$(PROTO_REPO)/$(COMMENT_PROTO_TAG)/$(COMMENT_PROTO_NAME)" $(DOWN_OUT) "$@" - -$(TMP_DIR)/$(USER_PROTO_NAME): | $(TMP_DIR) - $(DOWN) "$(PROTO_REPO)/$(USER_PROTO_TAG)/$(USER_PROTO_NAME)" $(DOWN_OUT) "$@" - -$(TMP_DIR)/$(RATING_PROTO_NAME): | $(TMP_DIR) - $(DOWN) "$(PROTO_REPO)/$(RATING_PROTO_TAG)/$(RATING_PROTO_NAME)" $(DOWN_OUT) "$@" - -$(TMP_DIR)/$(MOD_PROTO_NAME): | $(TMP_DIR) - $(DOWN) "$(PROTO_REPO)/$(MOD_PROTO_TAG)/$(MOD_PROTO_NAME)" $(DOWN_OUT) "$@" - - -clean: - $(RM) - -update-%: $(TMP_DIR)/%.proto | $(OUT_DIR) - $(MKDIR) "$(OUT_DIR)" - pdm run python -m grpc_tools.protoc \ - --proto_path="$(TMP_DIR)" \ - --python_out="$(OUT_DIR)" \ - --grpc_python_out="$(OUT_DIR)" \ - --pyi_out="$(OUT_DIR)" \ - "$(TMP_DIR)/$*.proto" - $(FIX_IMPORTS) - $(MAKE) clean - -run: - ENV=dev PYTHONPATH=src ./load_envs.sh pdm run python -u -m gateway.server - -format: - black . - isort . - ruff check . --fix - -lint: - black --check . - isort . --check --diff - flake8 . - ruff check . - mypy --strict . - -test: - pytest - -dev-check: format lint test diff --git a/justfile b/justfile new file mode 100644 index 0000000..2bb2ad5 --- /dev/null +++ b/justfile @@ -0,0 +1,37 @@ +set windows-shell := ["sh", "-c"] +set dotenv-load := true + +COMMON_JUST_URL := 'https://raw.githubusercontent.com/esclient/tools/refs/heads/main/python/common.just' +LOAD_ENVS_URL := 'https://raw.githubusercontent.com/esclient/tools/refs/heads/main/load_envs.sh' + +PROTO_REPO := 'https://raw.githubusercontent.com/esclient/protos' + +COMMENT_PROTO_TAG := 'v0.0.8' +COMMENT_PROTO_NAME := 'comment.proto' + +USER_PROTO_TAG := 'v0.0.8' +USER_PROTO_NAME := 'user.proto' + +RATING_PROTO_TAG := 'v0.0.15' +RATING_PROTO_NAME := 'rating.proto' + +MOD_PROTO_TAG := 'v0.1.2' +MOD_PROTO_NAME := 'mod.proto' + +TMP_DIR := '.proto' +OUT_DIR := 'src/apigateway/stubs' + +MKDIR_TOOLS := 'mkdir -p tools' + +FETCH_COMMON_JUST := 'curl -fsSL ' + COMMON_JUST_URL + ' -o tools/common.just' +FETCH_LOAD_ENVS := 'curl -fsSL ' + LOAD_ENVS_URL + ' -o tools/load_envs.sh' + +import? 'tools/common.just' + +default: + @just --list + +fetch-tools: + {{ MKDIR_TOOLS }} + {{ FETCH_COMMON_JUST }} + {{ FETCH_LOAD_ENVS }} diff --git a/pyproject.toml b/pyproject.toml index c6b1adc..0cb2e29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ exclude = ''' | venv | build | dist - | src/gateway/stubs + | src/apigateway/stubs )/ ''' @@ -26,7 +26,7 @@ include_trailing_comma = true force_grid_wrap = 0 use_parentheses = true ensure_newline_before_comments = true -skip = [".venv", "src/gateway/stubs"] +skip = [".venv", "src/apigateway/stubs"] [tool.flake8] max-line-length = 120 @@ -34,21 +34,21 @@ extend-ignore = ["E203", "W503", "E501"] per-file-ignores = [ "__init__.py:F401", "tests/*:T20,ARG001", - "src/gateway/stubs/*:E501,ARG001,ARG002" + "src/apigateway/stubs/*:E501,ARG001,ARG002" ] exclude = [ ".venv", "__pycache__", "build", "dist", - "src/gateway/stubs", + "src/apigateway/stubs", ] [tool.ruff] line-length = 120 target-version = "py313" preview = true -exclude = [".venv", "build", "dist", "src/gateway/stubs"] +exclude = [".venv", "build", "dist", "src/apigateway/stubs"] [tool.ruff.lint] select = [ @@ -77,8 +77,8 @@ extend-ignore = [ [tool.ruff.lint.per-file-ignores] "tests/*" = ["T20", "ARG001"] -"src/gateway/resolvers/*" = ["ARG001", "ARG002"] -"src/gateway/stubs/*" = ["E501","ARG001", "ARG002"] +"src/apigateway/resolvers/*" = ["ARG001", "ARG002"] +"src/apigateway/stubs/*" = ["E501","ARG001", "ARG002"] [tool.mypy] python_version = "3.13" @@ -97,7 +97,7 @@ mypy_path = ["src"] plugins = ["pydantic.mypy"] [[tool.mypy.overrides]] -module = ["gateway.stubs.*"] +module = ["apigateway.stubs.*"] ignore_errors = true [project] diff --git a/src/gateway/clients/base_client.py b/src/apigateway/clients/base_client.py similarity index 97% rename from src/gateway/clients/base_client.py rename to src/apigateway/clients/base_client.py index d818e79..d410c10 100644 --- a/src/gateway/clients/base_client.py +++ b/src/apigateway/clients/base_client.py @@ -1,12 +1,12 @@ import logging -from typing import Self from collections.abc import Awaitable, Callable +from typing import Self import grpc import grpc.aio from google.protobuf import message as _message -from ..helpers.retry import grpc_retry +from apigateway.helpers.retry import grpc_retry logger = logging.getLogger(__name__) diff --git a/src/gateway/clients/client_factory.py b/src/apigateway/clients/client_factory.py similarity index 89% rename from src/gateway/clients/client_factory.py rename to src/apigateway/clients/client_factory.py index a585626..9522360 100644 --- a/src/gateway/clients/client_factory.py +++ b/src/apigateway/clients/client_factory.py @@ -1,8 +1,8 @@ import grpc -from gateway.clients.comment import CommentServiceClient -from gateway.clients.mod import ModServiceClient -from gateway.clients.rating import RatingServiceClient +from apigateway.clients.comment import CommentServiceClient +from apigateway.clients.mod import ModServiceClient +from apigateway.clients.rating import RatingServiceClient class GrpcClientFactory: diff --git a/src/gateway/clients/comment.py b/src/apigateway/clients/comment.py similarity index 90% rename from src/gateway/clients/comment.py rename to src/apigateway/clients/comment.py index 8447c97..da95e41 100644 --- a/src/gateway/clients/comment.py +++ b/src/apigateway/clients/comment.py @@ -1,8 +1,5 @@ - - -from gateway.stubs import comment_pb2, comment_pb2_grpc - -from .base_client import GrpcClient +from apigateway.clients.base_client import GrpcClient +from apigateway.stubs.comment import comment_pb2, comment_pb2_grpc class CommentServiceClient(GrpcClient): diff --git a/src/gateway/clients/mod.py b/src/apigateway/clients/mod.py similarity index 90% rename from src/gateway/clients/mod.py rename to src/apigateway/clients/mod.py index 749877f..464ec26 100644 --- a/src/gateway/clients/mod.py +++ b/src/apigateway/clients/mod.py @@ -1,8 +1,5 @@ - - -from gateway.stubs import mod_pb2, mod_pb2_grpc - -from .base_client import GrpcClient +from apigateway.clients.base_client import GrpcClient +from apigateway.stubs.mod import mod_pb2, mod_pb2_grpc class ModServiceClient(GrpcClient): diff --git a/src/gateway/clients/rating.py b/src/apigateway/clients/rating.py similarity index 83% rename from src/gateway/clients/rating.py rename to src/apigateway/clients/rating.py index 4df61d5..423a627 100644 --- a/src/gateway/clients/rating.py +++ b/src/apigateway/clients/rating.py @@ -1,8 +1,5 @@ - - -from gateway.stubs import rating_pb2, rating_pb2_grpc - -from .base_client import GrpcClient +from apigateway.clients.base_client import GrpcClient +from apigateway.stubs.rating import rating_pb2, rating_pb2_grpc class RatingServiceClient(GrpcClient): diff --git a/src/gateway/converters/mod_status_converter.py b/src/apigateway/converters/mod_status_converter.py similarity index 93% rename from src/gateway/converters/mod_status_converter.py rename to src/apigateway/converters/mod_status_converter.py index fb8a8f7..e0bf449 100644 --- a/src/gateway/converters/mod_status_converter.py +++ b/src/apigateway/converters/mod_status_converter.py @@ -2,7 +2,7 @@ from enum import StrEnum from typing import Final -from gateway.stubs.mod_pb2 import ModStatus as ProtoModStatus +from apigateway.stubs.mod.mod_pb2 import ModStatus as ProtoModStatus class GraphQLModStatus(StrEnum): diff --git a/src/gateway/esclient_graphql.py b/src/apigateway/esclient_graphql.py similarity index 82% rename from src/gateway/esclient_graphql.py rename to src/apigateway/esclient_graphql.py index aa7bd70..9368514 100644 --- a/src/gateway/esclient_graphql.py +++ b/src/apigateway/esclient_graphql.py @@ -1,6 +1,6 @@ from typing import Any -from gateway.clients.base_client import GrpcClient +from apigateway.clients.base_client import GrpcClient class GQLContextViewer: diff --git a/src/gateway/helpers/id_helper.py b/src/apigateway/helpers/id_helper.py similarity index 100% rename from src/gateway/helpers/id_helper.py rename to src/apigateway/helpers/id_helper.py diff --git a/src/gateway/helpers/retry.py b/src/apigateway/helpers/retry.py similarity index 100% rename from src/gateway/helpers/retry.py rename to src/apigateway/helpers/retry.py diff --git a/src/gateway/resolvers/grpc_error_wrapper.py b/src/apigateway/resolvers/grpc_error_wrapper.py similarity index 100% rename from src/gateway/resolvers/grpc_error_wrapper.py rename to src/apigateway/resolvers/grpc_error_wrapper.py diff --git a/src/gateway/resolvers/mutation/comment.py b/src/apigateway/resolvers/mutation/comment.py similarity index 97% rename from src/gateway/resolvers/mutation/comment.py rename to src/apigateway/resolvers/mutation/comment.py index 97e1902..cabbf52 100644 --- a/src/gateway/resolvers/mutation/comment.py +++ b/src/apigateway/resolvers/mutation/comment.py @@ -4,7 +4,7 @@ from graphql import GraphQLResolveInfo from pydantic import BaseModel, field_validator -from gateway.helpers.id_helper import validate_and_convert_id +from apigateway.helpers.id_helper import validate_and_convert_id from ..grpc_error_wrapper import handle_grpc_errors diff --git a/src/gateway/resolvers/mutation/mod.py b/src/apigateway/resolvers/mutation/mod.py similarity index 96% rename from src/gateway/resolvers/mutation/mod.py rename to src/apigateway/resolvers/mutation/mod.py index d343b64..2a2e1cc 100644 --- a/src/gateway/resolvers/mutation/mod.py +++ b/src/apigateway/resolvers/mutation/mod.py @@ -5,7 +5,7 @@ from graphql import GraphQLResolveInfo from pydantic import BaseModel, field_validator -from gateway.helpers.id_helper import validate_and_convert_id +from apigateway.helpers.id_helper import validate_and_convert_id from ..grpc_error_wrapper import handle_grpc_errors diff --git a/src/gateway/resolvers/mutation/rating.py b/src/apigateway/resolvers/mutation/rating.py similarity index 94% rename from src/gateway/resolvers/mutation/rating.py rename to src/apigateway/resolvers/mutation/rating.py index 8cc4c98..432c0d6 100644 --- a/src/gateway/resolvers/mutation/rating.py +++ b/src/apigateway/resolvers/mutation/rating.py @@ -5,7 +5,7 @@ from graphql import GraphQLResolveInfo from pydantic import BaseModel, field_validator -from gateway.helpers.id_helper import validate_and_convert_id +from apigateway.helpers.id_helper import validate_and_convert_id from ..grpc_error_wrapper import handle_grpc_errors diff --git a/src/gateway/resolvers/mutation/root.py b/src/apigateway/resolvers/mutation/root.py similarity index 100% rename from src/gateway/resolvers/mutation/root.py rename to src/apigateway/resolvers/mutation/root.py diff --git a/src/gateway/resolvers/query/comment.py b/src/apigateway/resolvers/query/comment.py similarity index 95% rename from src/gateway/resolvers/query/comment.py rename to src/apigateway/resolvers/query/comment.py index 00942ae..adcdd9f 100644 --- a/src/gateway/resolvers/query/comment.py +++ b/src/apigateway/resolvers/query/comment.py @@ -4,7 +4,7 @@ from graphql import GraphQLResolveInfo from pydantic import BaseModel, field_validator -from gateway.helpers.id_helper import validate_and_convert_id +from apigateway.helpers.id_helper import validate_and_convert_id from ..grpc_error_wrapper import handle_grpc_errors diff --git a/src/gateway/resolvers/query/mod.py b/src/apigateway/resolvers/query/mod.py similarity index 90% rename from src/gateway/resolvers/query/mod.py rename to src/apigateway/resolvers/query/mod.py index a91f488..2fe6012 100644 --- a/src/gateway/resolvers/query/mod.py +++ b/src/apigateway/resolvers/query/mod.py @@ -4,8 +4,8 @@ from graphql import GraphQLResolveInfo from pydantic import BaseModel, field_validator -from gateway.converters.mod_status_converter import proto_to_graphql_mod_status -from gateway.helpers.id_helper import validate_and_convert_id +from apigateway.converters.mod_status_converter import proto_to_graphql_mod_status +from apigateway.helpers.id_helper import validate_and_convert_id from ..grpc_error_wrapper import handle_grpc_errors diff --git a/src/gateway/resolvers/query/root.py b/src/apigateway/resolvers/query/root.py similarity index 100% rename from src/gateway/resolvers/query/root.py rename to src/apigateway/resolvers/query/root.py diff --git a/src/gateway/schema/mutation/comment.graphql b/src/apigateway/schema/mutation/comment.graphql similarity index 100% rename from src/gateway/schema/mutation/comment.graphql rename to src/apigateway/schema/mutation/comment.graphql diff --git a/src/gateway/schema/mutation/mod.graphql b/src/apigateway/schema/mutation/mod.graphql similarity index 100% rename from src/gateway/schema/mutation/mod.graphql rename to src/apigateway/schema/mutation/mod.graphql diff --git a/src/gateway/schema/mutation/rating.graphql b/src/apigateway/schema/mutation/rating.graphql similarity index 100% rename from src/gateway/schema/mutation/rating.graphql rename to src/apigateway/schema/mutation/rating.graphql diff --git a/src/gateway/schema/query/comment.graphql b/src/apigateway/schema/query/comment.graphql similarity index 100% rename from src/gateway/schema/query/comment.graphql rename to src/apigateway/schema/query/comment.graphql diff --git a/src/gateway/schema/query/mod.graphql b/src/apigateway/schema/query/mod.graphql similarity index 100% rename from src/gateway/schema/query/mod.graphql rename to src/apigateway/schema/query/mod.graphql diff --git a/src/gateway/schema/schema.graphql b/src/apigateway/schema/schema.graphql similarity index 100% rename from src/gateway/schema/schema.graphql rename to src/apigateway/schema/schema.graphql diff --git a/src/gateway/server.py b/src/apigateway/server.py similarity index 78% rename from src/gateway/server.py rename to src/apigateway/server.py index 9f2b914..914d1d0 100644 --- a/src/gateway/server.py +++ b/src/apigateway/server.py @@ -6,14 +6,14 @@ from ariadne.asgi import GraphQL from ariadne.explorer import ExplorerGraphiQL -from gateway.clients.client_factory import GrpcClientFactory -from gateway.resolvers.mutation.comment import comment_mutation -from gateway.resolvers.mutation.mod import mod_mutation -from gateway.resolvers.mutation.root import mutation -from gateway.resolvers.query.comment import comment_query -from gateway.resolvers.query.mod import mod_query -from gateway.resolvers.query.root import query -from gateway.settings import Settings +from apigateway.clients.client_factory import GrpcClientFactory +from apigateway.resolvers.mutation.comment import comment_mutation +from apigateway.resolvers.mutation.mod import mod_mutation +from apigateway.resolvers.mutation.root import mutation +from apigateway.resolvers.query.comment import comment_query +from apigateway.resolvers.query.mod import mod_query +from apigateway.resolvers.query.root import query +from apigateway.settings import Settings from .esclient_graphql import GQLContextViewer @@ -22,7 +22,7 @@ settings = Settings() -type_defs = load_schema_from_path("src/gateway/schema") +type_defs = load_schema_from_path("src/apigateway/schema") schema = make_executable_schema( type_defs, diff --git a/src/gateway/settings.py b/src/apigateway/settings.py similarity index 100% rename from src/gateway/settings.py rename to src/apigateway/settings.py diff --git a/src/gateway/stubs/comment_pb2.py b/src/apigateway/stubs/comment/comment_pb2.py similarity index 100% rename from src/gateway/stubs/comment_pb2.py rename to src/apigateway/stubs/comment/comment_pb2.py diff --git a/src/gateway/stubs/comment_pb2.pyi b/src/apigateway/stubs/comment/comment_pb2.pyi similarity index 100% rename from src/gateway/stubs/comment_pb2.pyi rename to src/apigateway/stubs/comment/comment_pb2.pyi diff --git a/src/gateway/stubs/comment_pb2_grpc.py b/src/apigateway/stubs/comment/comment_pb2_grpc.py similarity index 99% rename from src/gateway/stubs/comment_pb2_grpc.py rename to src/apigateway/stubs/comment/comment_pb2_grpc.py index 574983d..cba8422 100644 --- a/src/gateway/stubs/comment_pb2_grpc.py +++ b/src/apigateway/stubs/comment/comment_pb2_grpc.py @@ -1,4 +1,4 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! """Client and server classes corresponding to protobuf-defined services.""" import grpc import warnings diff --git a/src/apigateway/stubs/mod/__init__.py b/src/apigateway/stubs/mod/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/gateway/stubs/mod_pb2.py b/src/apigateway/stubs/mod/mod_pb2.py similarity index 100% rename from src/gateway/stubs/mod_pb2.py rename to src/apigateway/stubs/mod/mod_pb2.py diff --git a/src/gateway/stubs/mod_pb2.pyi b/src/apigateway/stubs/mod/mod_pb2.pyi similarity index 100% rename from src/gateway/stubs/mod_pb2.pyi rename to src/apigateway/stubs/mod/mod_pb2.pyi diff --git a/src/gateway/stubs/mod_pb2_grpc.py b/src/apigateway/stubs/mod/mod_pb2_grpc.py similarity index 99% rename from src/gateway/stubs/mod_pb2_grpc.py rename to src/apigateway/stubs/mod/mod_pb2_grpc.py index 131fd6f..953d2e7 100644 --- a/src/gateway/stubs/mod_pb2_grpc.py +++ b/src/apigateway/stubs/mod/mod_pb2_grpc.py @@ -1,4 +1,4 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! """Client and server classes corresponding to protobuf-defined services.""" import grpc import warnings diff --git a/src/apigateway/stubs/rating/__init__.py b/src/apigateway/stubs/rating/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/gateway/stubs/rating_pb2.py b/src/apigateway/stubs/rating/rating_pb2.py similarity index 100% rename from src/gateway/stubs/rating_pb2.py rename to src/apigateway/stubs/rating/rating_pb2.py diff --git a/src/gateway/stubs/rating_pb2.pyi b/src/apigateway/stubs/rating/rating_pb2.pyi similarity index 100% rename from src/gateway/stubs/rating_pb2.pyi rename to src/apigateway/stubs/rating/rating_pb2.pyi diff --git a/src/gateway/stubs/rating_pb2_grpc.py b/src/apigateway/stubs/rating/rating_pb2_grpc.py similarity index 98% rename from src/gateway/stubs/rating_pb2_grpc.py rename to src/apigateway/stubs/rating/rating_pb2_grpc.py index 68bafff..97a99b2 100644 --- a/src/gateway/stubs/rating_pb2_grpc.py +++ b/src/apigateway/stubs/rating/rating_pb2_grpc.py @@ -1,4 +1,4 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! """Client and server classes corresponding to protobuf-defined services.""" import grpc import warnings diff --git a/src/apigateway/stubs/user/__init__.py b/src/apigateway/stubs/user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/apigateway/stubs/user/user_pb2.py b/src/apigateway/stubs/user/user_pb2.py new file mode 100644 index 0000000..d2bff77 --- /dev/null +++ b/src/apigateway/stubs/user/user_pb2.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: user.proto +# Protobuf Python Version: 6.31.1 +"""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, + 6, + 31, + 1, + '', + 'user.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nuser.proto\x12\x04user\"?\n\x10LoginUserRequest\x12\x19\n\x11username_or_email\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"_\n\x13RegisterUserRequest\x12\r\n\x05login\x18\x01 \x01(\t\x12\r\n\x05\x65mail\x18\x02 \x01(\t\x12\x10\n\x08password\x18\x03 \x01(\t\x12\x18\n\x10\x63onfirm_password\x18\x04 \x01(\t\"$\n\x11LoginUserResponse\x12\x0f\n\x07user_id\x18\x01 \x01(\x03\"\'\n\x14RegisterUserResponse\x12\x0f\n\x07user_id\x18\x01 \x01(\x03\x32\x92\x01\n\x0bUserService\x12<\n\tLoginUser\x12\x16.user.LoginUserRequest\x1a\x17.user.LoginUserResponse\x12\x45\n\x0cRegisterUser\x12\x19.user.RegisterUserRequest\x1a\x1a.user.RegisterUserResponseB\"Z github.com/esclient/user-serviceb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'user_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z github.com/esclient/user-service' + _globals['_LOGINUSERREQUEST']._serialized_start=20 + _globals['_LOGINUSERREQUEST']._serialized_end=83 + _globals['_REGISTERUSERREQUEST']._serialized_start=85 + _globals['_REGISTERUSERREQUEST']._serialized_end=180 + _globals['_LOGINUSERRESPONSE']._serialized_start=182 + _globals['_LOGINUSERRESPONSE']._serialized_end=218 + _globals['_REGISTERUSERRESPONSE']._serialized_start=220 + _globals['_REGISTERUSERRESPONSE']._serialized_end=259 + _globals['_USERSERVICE']._serialized_start=262 + _globals['_USERSERVICE']._serialized_end=408 +# @@protoc_insertion_point(module_scope) diff --git a/src/apigateway/stubs/user/user_pb2.pyi b/src/apigateway/stubs/user/user_pb2.pyi new file mode 100644 index 0000000..f744578 --- /dev/null +++ b/src/apigateway/stubs/user/user_pb2.pyi @@ -0,0 +1,37 @@ +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Optional as _Optional + +DESCRIPTOR: _descriptor.FileDescriptor + +class LoginUserRequest(_message.Message): + __slots__ = ("username_or_email", "password") + USERNAME_OR_EMAIL_FIELD_NUMBER: _ClassVar[int] + PASSWORD_FIELD_NUMBER: _ClassVar[int] + username_or_email: str + password: str + def __init__(self, username_or_email: _Optional[str] = ..., password: _Optional[str] = ...) -> None: ... + +class RegisterUserRequest(_message.Message): + __slots__ = ("login", "email", "password", "confirm_password") + LOGIN_FIELD_NUMBER: _ClassVar[int] + EMAIL_FIELD_NUMBER: _ClassVar[int] + PASSWORD_FIELD_NUMBER: _ClassVar[int] + CONFIRM_PASSWORD_FIELD_NUMBER: _ClassVar[int] + login: str + email: str + password: str + confirm_password: str + def __init__(self, login: _Optional[str] = ..., email: _Optional[str] = ..., password: _Optional[str] = ..., confirm_password: _Optional[str] = ...) -> None: ... + +class LoginUserResponse(_message.Message): + __slots__ = ("user_id",) + USER_ID_FIELD_NUMBER: _ClassVar[int] + user_id: int + def __init__(self, user_id: _Optional[int] = ...) -> None: ... + +class RegisterUserResponse(_message.Message): + __slots__ = ("user_id",) + USER_ID_FIELD_NUMBER: _ClassVar[int] + user_id: int + def __init__(self, user_id: _Optional[int] = ...) -> None: ... diff --git a/src/apigateway/stubs/user/user_pb2_grpc.py b/src/apigateway/stubs/user/user_pb2_grpc.py new file mode 100644 index 0000000..ee4f206 --- /dev/null +++ b/src/apigateway/stubs/user/user_pb2_grpc.py @@ -0,0 +1,140 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import user_pb2 as user__pb2 + +GRPC_GENERATED_VERSION = '1.75.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in user_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class UserServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.LoginUser = channel.unary_unary( + '/user.UserService/LoginUser', + request_serializer=user__pb2.LoginUserRequest.SerializeToString, + response_deserializer=user__pb2.LoginUserResponse.FromString, + _registered_method=True) + self.RegisterUser = channel.unary_unary( + '/user.UserService/RegisterUser', + request_serializer=user__pb2.RegisterUserRequest.SerializeToString, + response_deserializer=user__pb2.RegisterUserResponse.FromString, + _registered_method=True) + + +class UserServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def LoginUser(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def RegisterUser(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_UserServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'LoginUser': grpc.unary_unary_rpc_method_handler( + servicer.LoginUser, + request_deserializer=user__pb2.LoginUserRequest.FromString, + response_serializer=user__pb2.LoginUserResponse.SerializeToString, + ), + 'RegisterUser': grpc.unary_unary_rpc_method_handler( + servicer.RegisterUser, + request_deserializer=user__pb2.RegisterUserRequest.FromString, + response_serializer=user__pb2.RegisterUserResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'user.UserService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('user.UserService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class UserService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def LoginUser(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/user.UserService/LoginUser', + user__pb2.LoginUserRequest.SerializeToString, + user__pb2.LoginUserResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def RegisterUser(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/user.UserService/RegisterUser', + user__pb2.RegisterUserRequest.SerializeToString, + user__pb2.RegisterUserResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/tools/common.just b/tools/common.just new file mode 100644 index 0000000..883b36c --- /dev/null +++ b/tools/common.just @@ -0,0 +1,44 @@ +MKDIR := 'mkdir -p' +RM := 'rm -rf ' + TMP_DIR +DOWN := 'curl -fsSL' +DOWN_OUT := '-o' +PY_FIX_IMPORTS := 'for f in ' + OUT_DIR + '/*_pb2_grpc.py; do [ -f "$f" ] && sed -i "s/^import \\(.*_pb2\\)/from . import \\1/" "$f"; done' + +clean: + {{RM}} + +fetch-proto: + {{MKDIR}} "{{TMP_DIR}}" + {{DOWN}} "https://raw.githubusercontent.com/esclient/protos/{{PROTO_TAG}}/{{PROTO_NAME}}" {{DOWN_OUT}} "{{TMP_DIR}}/{{PROTO_NAME}}" + +run: + ENV=dev PYTHONPATH=src ./tools/load_envs.sh pdm run run-server + +gen-stubs: fetch-proto + {{MKDIR}} "{{OUT_DIR}}" + pdm run python -m grpc_tools.protoc \ + --proto_path="{{TMP_DIR}}" \ + --python_out="{{OUT_DIR}}" \ + --grpc_python_out="{{OUT_DIR}}" \ + --pyi_out="{{OUT_DIR}}" \ + "{{TMP_DIR}}/{{PROTO_NAME}}" + {{PY_FIX_IMPORTS}} + +update: gen-stubs clean + +format: + black . + isort . + ruff check . --fix + +lint: + black --check . + isort . --check --diff + flake8 . + ruff check . + mypy --strict . + +test: + pytest + +prepare: format lint test diff --git a/load_envs.sh b/tools/load_envs.sh similarity index 92% rename from load_envs.sh rename to tools/load_envs.sh index 716878d..cbc4a4b 100644 --- a/load_envs.sh +++ b/tools/load_envs.sh @@ -1,14 +1,14 @@ #!/bin/bash set -e -if [ -f .env ]; then +if [ "$ENV" = "prod" ] && [ -f .env ]; then export $(grep -v '^#' .env | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/"//g' | sed "s/'//g" | xargs) fi CONFIG="configs/${ENV}.yaml" [ ! -f "$CONFIG" ] && echo "ERROR: Config not found: $CONFIG" >&2 && exit 1 -eval "$(yq eval 'to_entries | .[] | "export " + .key + "=\"" + (.value | tostring) + "\""' "$CONFIG")" +eval "$(yq eval 'to_entries | .[] | "export " + .key + "='\''" + (.value | tostring) + "'\''"' "$CONFIG")" if [ "$ENV" = "dev" ]; then exec "$@" @@ -71,4 +71,3 @@ for var in $(env | grep '{vault:' | cut -d= -f1); do done exec "$@" - From b925740c1eaee773bf70ba7f201e7893bb8375dc Mon Sep 17 00:00:00 2001 From: Andrey Kataev Date: Tue, 14 Oct 2025 19:06:14 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=BF=D1=83=D1=82=D1=8C=20=D0=B4=D0=BE=20?= =?UTF-8?q?common.just?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- justfile | 2 +- tools/common.just | 36 +++++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/justfile b/justfile index 2bb2ad5..9d86fdc 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,7 @@ set windows-shell := ["sh", "-c"] set dotenv-load := true -COMMON_JUST_URL := 'https://raw.githubusercontent.com/esclient/tools/refs/heads/main/python/common.just' +COMMON_JUST_URL := 'https://raw.githubusercontent.com/esclient/tools/refs/heads/main/api-gateway/common.just' LOAD_ENVS_URL := 'https://raw.githubusercontent.com/esclient/tools/refs/heads/main/load_envs.sh' PROTO_REPO := 'https://raw.githubusercontent.com/esclient/protos' diff --git a/tools/common.just b/tools/common.just index 883b36c..83f286d 100644 --- a/tools/common.just +++ b/tools/common.just @@ -2,29 +2,39 @@ MKDIR := 'mkdir -p' RM := 'rm -rf ' + TMP_DIR DOWN := 'curl -fsSL' DOWN_OUT := '-o' -PY_FIX_IMPORTS := 'for f in ' + OUT_DIR + '/*_pb2_grpc.py; do [ -f "$f" ] && sed -i "s/^import \\(.*_pb2\\)/from . import \\1/" "$f"; done' clean: {{RM}} -fetch-proto: +fetch-proto tag name: {{MKDIR}} "{{TMP_DIR}}" - {{DOWN}} "https://raw.githubusercontent.com/esclient/protos/{{PROTO_TAG}}/{{PROTO_NAME}}" {{DOWN_OUT}} "{{TMP_DIR}}/{{PROTO_NAME}}" + {{DOWN}} "{{PROTO_REPO}}/{{tag}}/{{name}}" {{DOWN_OUT}} "{{TMP_DIR}}/{{name}}" run: - ENV=dev PYTHONPATH=src ./tools/load_envs.sh pdm run run-server + ENV=dev PYTHONPATH=src ./tools/load_envs.sh pdm run python -u -m apigateway.server -gen-stubs: fetch-proto - {{MKDIR}} "{{OUT_DIR}}" +gen-stubs name out_dir: + {{MKDIR}} "{{out_dir}}" pdm run python -m grpc_tools.protoc \ --proto_path="{{TMP_DIR}}" \ - --python_out="{{OUT_DIR}}" \ - --grpc_python_out="{{OUT_DIR}}" \ - --pyi_out="{{OUT_DIR}}" \ - "{{TMP_DIR}}/{{PROTO_NAME}}" - {{PY_FIX_IMPORTS}} - -update: gen-stubs clean + --python_out="{{out_dir}}" \ + --grpc_python_out="{{out_dir}}" \ + --pyi_out="{{out_dir}}" \ + "{{TMP_DIR}}/{{name}}" + for f in "{{out_dir}}"/*_pb2_grpc.py; do [ -f "$f" ] && sed -i 's/^import \(.*_pb2\)/from . import \1/' "$f"; done + + +update name: + case "{{name}}" in \ + comment) tag="{{COMMENT_PROTO_TAG}}"; proto="{{COMMENT_PROTO_NAME}}"; out="{{OUT_DIR}}/comment";; \ + user) tag="{{USER_PROTO_TAG}}"; proto="{{USER_PROTO_NAME}}"; out="{{OUT_DIR}}/user";; \ + rating) tag="{{RATING_PROTO_TAG}}"; proto="{{RATING_PROTO_NAME}}"; out="{{OUT_DIR}}/rating";; \ + mod) tag="{{MOD_PROTO_TAG}}"; proto="{{MOD_PROTO_NAME}}"; out="{{OUT_DIR}}/mod";; \ + *) echo "Unknown proto: {{name}} (expected: comment | user | rating | mod)" >&2; exit 1;; \ + esac; \ + just fetch-proto "$tag" "$proto"; \ + just gen-stubs "$proto" "$out"; \ + just clean format: black .