Get rid of all transport types and settle on Protobuf (#25)

* Get rid of all transport types and settle on Protobuf

hope i don't regret this

* Update Cargo.toml

* Update agent.py
This commit is contained in:
Josh Thomas 2024-12-12 16:53:49 -06:00 committed by GitHub
parent 643a47953e
commit 0a6e975ca5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 1484 additions and 685 deletions

12
python/djls/_typing.py Normal file
View file

@ -0,0 +1,12 @@
from __future__ import annotations
import sys
if sys.version_info >= (3, 12):
from typing import override as typing_override
else:
from typing_extensions import (
override as typing_override, # pyright: ignore[reportUnreachable]
)
override = typing_override

131
python/djls/agent.py Normal file
View file

@ -0,0 +1,131 @@
from __future__ import annotations
import logging
import struct
import sys
from google.protobuf.message import Message
from .commands import COMMANDS
from .commands import Command
from .proto.v1 import messages_pb2
logger = logging.getLogger("djls")
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler("/tmp/djls_debug.log")
fh.setLevel(logging.DEBUG)
ch = logging.StreamHandler(sys.stderr)
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh)
logger.addHandler(ch)
class LSPAgent:
def __init__(self):
self._commands: dict[str, Command] = {cmd.name: cmd() for cmd in COMMANDS}
logger.debug(
"LSPAgent initialized with commands: %s", list(self._commands.keys())
)
def serve(self):
print("ready", flush=True)
try:
import django
django.setup()
except Exception as e:
error_response = self.create_error(messages_pb2.Error.DJANGO_ERROR, str(e))
self.write_message(error_response)
while True:
try:
data = self.read_message()
if not data:
break
response = self.handle_request(data)
self.write_message(response)
except Exception as e:
error_response = self.create_error(messages_pb2.Error.UNKNOWN, str(e))
self.write_message(error_response)
def read_message(self) -> bytes | None:
length_bytes = sys.stdin.buffer.read(4)
logger.debug("Read length bytes: %r", length_bytes)
if not length_bytes:
return None
length = struct.unpack(">I", length_bytes)[0]
logger.debug("Unpacked length: %d", length)
data = sys.stdin.buffer.read(length)
logger.debug("Read data bytes: %r", data)
return data
def handle_request(self, request_data: bytes) -> Message:
request = messages_pb2.Request()
request.ParseFromString(request_data)
command_name = request.WhichOneof("command")
logger.debug("Command name: %s", command_name)
command = self._commands.get(command_name)
if not command:
logger.error("Unknown command: %s", command_name)
return self.create_error(
messages_pb2.Error.INVALID_REQUEST, f"Unknown command: {command_name}"
)
try:
result = command.execute(getattr(request, command_name))
return messages_pb2.Response(**{command_name: result})
except Exception as e:
logger.exception("Error executing command")
return self.create_error(messages_pb2.Error.UNKNOWN, str(e))
def write_message(self, message: Message) -> None:
data = message.SerializeToString()
logger.debug(f"Sending response, length: {len(data)}, data: {data!r}")
length = struct.pack(">I", len(data))
logger.debug(f"Length bytes: {length!r}")
sys.stdout.buffer.write(length)
sys.stdout.buffer.write(data)
sys.stdout.buffer.flush()
def create_error(
self, code: messages_pb2.Error.Code, message: str
) -> messages_pb2.Response:
response = messages_pb2.Response()
response.error.code = code
response.error.message = message
return response
def main() -> None:
logger.debug("Starting DJLS...")
try:
logger.debug("Initializing LSPAgent...")
agent = LSPAgent()
logger.debug("Starting LSPAgent serve...")
agent.serve()
except KeyboardInterrupt:
logger.debug("Received KeyboardInterrupt")
sys.exit(0)
except Exception as e:
logger.exception("Fatal error")
print(f"error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

209
python/djls/commands.py Normal file
View file

@ -0,0 +1,209 @@
from __future__ import annotations
import importlib.metadata
import os
import sys
import sysconfig
from abc import ABC
from abc import abstractmethod
from typing import ClassVar
from typing import Generic
from typing import TypeVar
from google.protobuf.message import Message
from ._typing import override
from .proto.v1 import check_pb2
from .proto.v1 import django_pb2
from .proto.v1 import python_pb2
Request = TypeVar("Request", bound=Message)
Response = TypeVar("Response", bound=Message)
class Command(ABC, Generic[Request, Response]):
name: ClassVar[str]
request: ClassVar[type[Message]]
response: ClassVar[type[Message]]
def __init_subclass__(cls) -> None:
super().__init_subclass__()
class_vars = ["name", "request", "response"]
for class_var in class_vars:
if not hasattr(cls, class_var):
raise TypeError(
f"Command subclass {cls.__name__} must define '{class_var}'"
)
@abstractmethod
def execute(self, request: Request) -> Response: ...
class CheckHealth(Command[check_pb2.HealthRequest, check_pb2.HealthResponse]):
name = "check__health"
request = check_pb2.HealthRequest
response = check_pb2.HealthResponse
@override
def execute(self, request: check_pb2.HealthRequest) -> check_pb2.HealthResponse:
return check_pb2.HealthResponse(passed=True)
class CheckDjangoAvailable(
Command[check_pb2.DjangoAvailableRequest, check_pb2.DjangoAvailableResponse]
):
name = "check__django_available"
request = check_pb2.DjangoAvailableRequest
response = check_pb2.DjangoAvailableResponse
@override
def execute(
self, request: check_pb2.DjangoAvailableRequest
) -> check_pb2.DjangoAvailableResponse:
try:
import django
return check_pb2.DjangoAvailableResponse(passed=True)
except ImportError:
return check_pb2.DjangoAvailableResponse(
passed=False, error="Django is not installed"
)
class CheckAppInstalled(
Command[check_pb2.AppInstalledRequest, check_pb2.AppInstalledResponse]
):
name = "check__app_installed"
request = check_pb2.AppInstalledRequest
response = check_pb2.AppInstalledResponse
@override
def execute(
self, request: check_pb2.AppInstalledRequest
) -> check_pb2.AppInstalledResponse:
try:
from django.apps import apps
return check_pb2.AppInstalledResponse(
passed=apps.is_installed(request.app_name)
)
except ImportError:
return check_pb2.AppInstalledResponse(
passed=False, error="Django is not installed"
)
class PythonGetEnvironment(
Command[python_pb2.GetEnvironmentRequest, python_pb2.GetEnvironmentResponse]
):
name = "python__get_environment"
request = python_pb2.GetEnvironmentRequest
response = python_pb2.GetEnvironmentResponse
@override
def execute(
self, request: python_pb2.GetEnvironmentRequest
) -> python_pb2.GetEnvironmentResponse:
packages = {}
for dist in importlib.metadata.distributions():
try:
requires = []
try:
requires = list(dist.requires) if hasattr(dist, "requires") else []
except Exception:
pass
location = None
try:
location = str(dist._path) if hasattr(dist, "_path") else None
except Exception:
pass
packages[dist.metadata["Name"]] = python_pb2.Package(
dist_name=dist.metadata["Name"],
dist_version=dist.metadata["Version"],
dist_location=location,
dist_requires=requires,
dist_requires_python=dist.metadata.get("Requires-Python"),
dist_entry_points=str(dist.entry_points)
if hasattr(dist, "entry_points")
else None,
)
except Exception:
continue
sysconfig_paths = sysconfig.get_paths()
version_info = python_pb2.VersionInfo(
major=sys.version_info.major,
minor=sys.version_info.minor,
micro=sys.version_info.micro,
releaselevel={
"alpha": python_pb2.ReleaseLevel.ALPHA,
"beta": python_pb2.ReleaseLevel.BETA,
"candidate": python_pb2.ReleaseLevel.CANDIDATE,
"final": python_pb2.ReleaseLevel.FINAL,
}[sys.version_info.releaselevel],
serial=sys.version_info.serial,
)
return python_pb2.GetEnvironmentResponse(
python=python_pb2.Python(
os=python_pb2.Os(environ={k: v for k, v in os.environ.items()}),
site=python_pb2.Site(packages=packages),
sys=python_pb2.Sys(
debug_build=hasattr(sys, "gettotalrefcount"),
dev_mode=sys.flags.dev_mode,
is_venv=sys.prefix != sys.base_prefix,
abiflags=sys.abiflags,
base_prefix=sys.base_prefix,
default_encoding=sys.getdefaultencoding(),
executable=sys.executable,
filesystem_encoding=sys.getfilesystemencoding(),
implementation_name=sys.implementation.name,
platform=sys.platform,
prefix=sys.prefix,
builtin_module_names=list(sys.builtin_module_names),
dll_paths=sys.path if sys.platform == "win32" else [],
path=sys.path,
version_info=version_info,
),
sysconfig=python_pb2.Sysconfig(
data=sysconfig_paths.get("data", ""),
include=sysconfig_paths.get("include", ""),
platinclude=sysconfig_paths.get("platinclude", ""),
platlib=sysconfig_paths.get("platlib", ""),
platstdlib=sysconfig_paths.get("platstdlib", ""),
purelib=sysconfig_paths.get("purelib", ""),
scripts=sysconfig_paths.get("scripts", ""),
stdlib=sysconfig_paths.get("stdlib", ""),
),
)
)
class DjangoGetProjectInfo(
Command[django_pb2.GetProjectInfoRequest, django_pb2.GetProjectInfoResponse]
):
name = "django__get_project_info"
request = django_pb2.GetProjectInfoRequest
response = django_pb2.GetProjectInfoResponse
@override
def execute(
self, request: django_pb2.GetProjectInfoRequest
) -> django_pb2.GetProjectInfoResponse:
import django
return django_pb2.GetProjectInfoResponse(
project=django_pb2.Project(version=django.__version__)
)
COMMANDS = [
CheckAppInstalled,
CheckDjangoAvailable,
CheckHealth,
PythonGetEnvironment,
DjangoGetProjectInfo,
]

View file

@ -9,34 +9,6 @@ from .scripts import has_import
from .scripts import python_setup
def handle_command(command: str) -> str:
parts = command.strip().split()
command = parts[0]
args = parts[1:] if len(parts) > 1 else []
if command == "django_setup":
return json.dumps(django_setup.get_django_setup_info())
if command == "has_import":
if not args:
return "error: Missing module name argument"
return json.dumps({"can_import": has_import.check_import(args[0])})
if command == "health":
return "ok"
if command == "installed_apps_check":
import django
from django.conf import settings
django.setup()
if not args:
return "error: Missing module name argument"
return json.dumps({"has_app": args[0] in settings.INSTALLED_APPS})
if command == "python_setup":
return json.dumps(python_setup.get_python_info())
if command == "version":
return "0.1.0"
return f"Unknown command: {command}"
def handle_json_command(data: dict[str, Any]) -> dict[str, Any]:
command = data["command"]
args = data.get("args", []) # Get args if they exist
@ -84,20 +56,12 @@ def main():
if not line:
break
if transport_type == "json":
data = json.loads(line)
response = handle_json_command(data)
print(json.dumps(response), flush=True)
else:
command = line.strip()
response = handle_command(command)
print(response, flush=True)
data = json.loads(line)
response = handle_json_command(data)
print(json.dumps(response), flush=True)
except Exception as e:
if transport_type == "json":
print(json.dumps({"status": "error", "error": str(e)}), flush=True)
else:
print(f"error: {str(e)}", flush=True)
print(json.dumps({"status": "error", "error": str(e)}), flush=True)
if __name__ == "__main__":

View file

@ -1,46 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: messages.proto
# Protobuf Python Version: 5.29.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,
5,
29,
1,
'',
'messages.proto'
)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0emessages.proto\x12\x04\x64jls\"c\n\x07ToAgent\x12)\n\x0chealth_check\x18\x01 \x01(\x0b\x32\x11.djls.HealthCheckH\x00\x12\"\n\x08shutdown\x18\x02 \x01(\x0b\x32\x0e.djls.ShutdownH\x00\x42\t\n\x07\x63ommand\"\r\n\x0bHealthCheck\"\n\n\x08Shutdown\"g\n\tFromAgent\x12\x31\n\x0chealth_check\x18\x01 \x01(\x0b\x32\x19.djls.HealthCheckResponseH\x00\x12\x1c\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x0b.djls.ErrorH\x00\x42\t\n\x07message\"\x15\n\x13HealthCheckResponse\"+\n\x05\x45rror\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x11\n\ttraceback\x18\x02 \x01(\tb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'messages_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
DESCRIPTOR._loaded_options = None
_globals['_TOAGENT']._serialized_start=24
_globals['_TOAGENT']._serialized_end=123
_globals['_HEALTHCHECK']._serialized_start=125
_globals['_HEALTHCHECK']._serialized_end=138
_globals['_SHUTDOWN']._serialized_start=140
_globals['_SHUTDOWN']._serialized_end=150
_globals['_FROMAGENT']._serialized_start=152
_globals['_FROMAGENT']._serialized_end=255
_globals['_HEALTHCHECKRESPONSE']._serialized_start=257
_globals['_HEALTHCHECKRESPONSE']._serialized_end=278
_globals['_ERROR']._serialized_start=280
_globals['_ERROR']._serialized_end=323
# @@protoc_insertion_point(module_scope)

View file

@ -0,0 +1,4 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: generated by py-init

View file

@ -0,0 +1,50 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/check.proto
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: v1/check.proto
# Protobuf Python Version: 5.29.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,
5,
29,
1,
'',
'v1/check.proto'
)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0ev1/check.proto\x12\rdjls.v1.check\"\x0f\n\rHealthRequest\">\n\x0eHealthResponse\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\x18\n\x16\x44jangoAvailableRequest\"G\n\x17\x44jangoAvailableResponse\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\'\n\x13\x41ppInstalledRequest\x12\x10\n\x08\x61pp_name\x18\x01 \x01(\t\"D\n\x14\x41ppInstalledResponse\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_errorb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.check_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
DESCRIPTOR._loaded_options = None
_globals['_HEALTHREQUEST']._serialized_start=33
_globals['_HEALTHREQUEST']._serialized_end=48
_globals['_HEALTHRESPONSE']._serialized_start=50
_globals['_HEALTHRESPONSE']._serialized_end=112
_globals['_DJANGOAVAILABLEREQUEST']._serialized_start=114
_globals['_DJANGOAVAILABLEREQUEST']._serialized_end=138
_globals['_DJANGOAVAILABLERESPONSE']._serialized_start=140
_globals['_DJANGOAVAILABLERESPONSE']._serialized_end=211
_globals['_APPINSTALLEDREQUEST']._serialized_start=213
_globals['_APPINSTALLEDREQUEST']._serialized_end=252
_globals['_APPINSTALLEDRESPONSE']._serialized_start=254
_globals['_APPINSTALLEDRESPONSE']._serialized_end=322
# @@protoc_insertion_point(module_scope)

View file

@ -0,0 +1,47 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/check.proto
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 HealthRequest(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class HealthResponse(_message.Message):
__slots__ = ("passed", "error")
PASSED_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
passed: bool
error: str
def __init__(self, passed: bool = ..., error: _Optional[str] = ...) -> None: ...
class DjangoAvailableRequest(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class DjangoAvailableResponse(_message.Message):
__slots__ = ("passed", "error")
PASSED_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
passed: bool
error: str
def __init__(self, passed: bool = ..., error: _Optional[str] = ...) -> None: ...
class AppInstalledRequest(_message.Message):
__slots__ = ("app_name",)
APP_NAME_FIELD_NUMBER: _ClassVar[int]
app_name: str
def __init__(self, app_name: _Optional[str] = ...) -> None: ...
class AppInstalledResponse(_message.Message):
__slots__ = ("passed", "error")
PASSED_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
passed: bool
error: str
def __init__(self, passed: bool = ..., error: _Optional[str] = ...) -> None: ...

View file

@ -0,0 +1,44 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/django.proto
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: v1/django.proto
# Protobuf Python Version: 5.29.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,
5,
29,
1,
'',
'v1/django.proto'
)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0fv1/django.proto\x12\x0e\x64jls.v1.django\"\x1a\n\x07Project\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x17\n\x15GetProjectInfoRequest\"B\n\x16GetProjectInfoResponse\x12(\n\x07project\x18\x01 \x01(\x0b\x32\x17.djls.v1.django.Projectb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.django_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
DESCRIPTOR._loaded_options = None
_globals['_PROJECT']._serialized_start=35
_globals['_PROJECT']._serialized_end=61
_globals['_GETPROJECTINFOREQUEST']._serialized_start=63
_globals['_GETPROJECTINFOREQUEST']._serialized_end=86
_globals['_GETPROJECTINFORESPONSE']._serialized_start=88
_globals['_GETPROJECTINFORESPONSE']._serialized_end=154
# @@protoc_insertion_point(module_scope)

View file

@ -0,0 +1,25 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/django.proto
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 Project(_message.Message):
__slots__ = ("version",)
VERSION_FIELD_NUMBER: _ClassVar[int]
version: str
def __init__(self, version: _Optional[str] = ...) -> None: ...
class GetProjectInfoRequest(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class GetProjectInfoResponse(_message.Message):
__slots__ = ("project",)
PROJECT_FIELD_NUMBER: _ClassVar[int]
project: Project
def __init__(self, project: _Optional[_Union[Project, _Mapping]] = ...) -> None: ...

View file

@ -0,0 +1,49 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/messages.proto
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: v1/messages.proto
# Protobuf Python Version: 5.29.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,
5,
29,
1,
'',
'v1/messages.proto'
)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
from . import check_pb2 as v1_dot_check__pb2
from . import django_pb2 as v1_dot_django__pb2
from . import python_pb2 as v1_dot_python__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11v1/messages.proto\x12\x10\x64jls.v1.messages\x1a\x0ev1/check.proto\x1a\x0fv1/django.proto\x1a\x0fv1/python.proto\"\xf0\x02\n\x07Request\x12\x35\n\rcheck__health\x18\x01 \x01(\x0b\x32\x1c.djls.v1.check.HealthRequestH\x00\x12H\n\x17\x63heck__django_available\x18\x02 \x01(\x0b\x32%.djls.v1.check.DjangoAvailableRequestH\x00\x12\x42\n\x14\x63heck__app_installed\x18\x03 \x01(\x0b\x32\".djls.v1.check.AppInstalledRequestH\x00\x12I\n\x17python__get_environment\x18\xe8\x07 \x01(\x0b\x32%.djls.v1.python.GetEnvironmentRequestH\x00\x12J\n\x18\x64jango__get_project_info\x18\xd0\x0f \x01(\x0b\x32%.djls.v1.django.GetProjectInfoRequestH\x00\x42\t\n\x07\x63ommand\"\xa0\x03\n\x08Response\x12\x36\n\rcheck__health\x18\x01 \x01(\x0b\x32\x1d.djls.v1.check.HealthResponseH\x00\x12I\n\x17\x63heck__django_available\x18\x02 \x01(\x0b\x32&.djls.v1.check.DjangoAvailableResponseH\x00\x12\x43\n\x14\x63heck__app_installed\x18\x03 \x01(\x0b\x32#.djls.v1.check.AppInstalledResponseH\x00\x12J\n\x17python__get_environment\x18\xe8\x07 \x01(\x0b\x32&.djls.v1.python.GetEnvironmentResponseH\x00\x12K\n\x18\x64jango__get_project_info\x18\xd0\x0f \x01(\x0b\x32&.djls.v1.django.GetProjectInfoResponseH\x00\x12)\n\x05\x65rror\x18\xa8\x46 \x01(\x0b\x32\x17.djls.v1.messages.ErrorH\x00\x42\x08\n\x06result\"\xa5\x01\n\x05\x45rror\x12*\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1c.djls.v1.messages.Error.Code\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\ttraceback\x18\x03 \x01(\t\"L\n\x04\x43ode\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x13\n\x0fINVALID_REQUEST\x10\x01\x12\x10\n\x0cPYTHON_ERROR\x10\x02\x12\x10\n\x0c\x44JANGO_ERROR\x10\x03\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.messages_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
DESCRIPTOR._loaded_options = None
_globals['_REQUEST']._serialized_start=90
_globals['_REQUEST']._serialized_end=458
_globals['_RESPONSE']._serialized_start=461
_globals['_RESPONSE']._serialized_end=877
_globals['_ERROR']._serialized_start=880
_globals['_ERROR']._serialized_end=1045
_globals['_ERROR_CODE']._serialized_start=969
_globals['_ERROR_CODE']._serialized_end=1045
# @@protoc_insertion_point(module_scope)

View file

@ -0,0 +1,63 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/messages.proto
from . import check_pb2 as _check_pb2
from . import django_pb2 as _django_pb2
from . import python_pb2 as _python_pb2
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
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 Request(_message.Message):
__slots__ = ("check__health", "check__django_available", "check__app_installed", "python__get_environment", "django__get_project_info")
CHECK__HEALTH_FIELD_NUMBER: _ClassVar[int]
CHECK__DJANGO_AVAILABLE_FIELD_NUMBER: _ClassVar[int]
CHECK__APP_INSTALLED_FIELD_NUMBER: _ClassVar[int]
PYTHON__GET_ENVIRONMENT_FIELD_NUMBER: _ClassVar[int]
DJANGO__GET_PROJECT_INFO_FIELD_NUMBER: _ClassVar[int]
check__health: _check_pb2.HealthRequest
check__django_available: _check_pb2.DjangoAvailableRequest
check__app_installed: _check_pb2.AppInstalledRequest
python__get_environment: _python_pb2.GetEnvironmentRequest
django__get_project_info: _django_pb2.GetProjectInfoRequest
def __init__(self, check__health: _Optional[_Union[_check_pb2.HealthRequest, _Mapping]] = ..., check__django_available: _Optional[_Union[_check_pb2.DjangoAvailableRequest, _Mapping]] = ..., check__app_installed: _Optional[_Union[_check_pb2.AppInstalledRequest, _Mapping]] = ..., python__get_environment: _Optional[_Union[_python_pb2.GetEnvironmentRequest, _Mapping]] = ..., django__get_project_info: _Optional[_Union[_django_pb2.GetProjectInfoRequest, _Mapping]] = ...) -> None: ...
class Response(_message.Message):
__slots__ = ("check__health", "check__django_available", "check__app_installed", "python__get_environment", "django__get_project_info", "error")
CHECK__HEALTH_FIELD_NUMBER: _ClassVar[int]
CHECK__DJANGO_AVAILABLE_FIELD_NUMBER: _ClassVar[int]
CHECK__APP_INSTALLED_FIELD_NUMBER: _ClassVar[int]
PYTHON__GET_ENVIRONMENT_FIELD_NUMBER: _ClassVar[int]
DJANGO__GET_PROJECT_INFO_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
check__health: _check_pb2.HealthResponse
check__django_available: _check_pb2.DjangoAvailableResponse
check__app_installed: _check_pb2.AppInstalledResponse
python__get_environment: _python_pb2.GetEnvironmentResponse
django__get_project_info: _django_pb2.GetProjectInfoResponse
error: Error
def __init__(self, check__health: _Optional[_Union[_check_pb2.HealthResponse, _Mapping]] = ..., check__django_available: _Optional[_Union[_check_pb2.DjangoAvailableResponse, _Mapping]] = ..., check__app_installed: _Optional[_Union[_check_pb2.AppInstalledResponse, _Mapping]] = ..., python__get_environment: _Optional[_Union[_python_pb2.GetEnvironmentResponse, _Mapping]] = ..., django__get_project_info: _Optional[_Union[_django_pb2.GetProjectInfoResponse, _Mapping]] = ..., error: _Optional[_Union[Error, _Mapping]] = ...) -> None: ...
class Error(_message.Message):
__slots__ = ("code", "message", "traceback")
class Code(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
UNKNOWN: _ClassVar[Error.Code]
INVALID_REQUEST: _ClassVar[Error.Code]
PYTHON_ERROR: _ClassVar[Error.Code]
DJANGO_ERROR: _ClassVar[Error.Code]
UNKNOWN: Error.Code
INVALID_REQUEST: Error.Code
PYTHON_ERROR: Error.Code
DJANGO_ERROR: Error.Code
CODE_FIELD_NUMBER: _ClassVar[int]
MESSAGE_FIELD_NUMBER: _ClassVar[int]
TRACEBACK_FIELD_NUMBER: _ClassVar[int]
code: Error.Code
message: str
traceback: str
def __init__(self, code: _Optional[_Union[Error.Code, str]] = ..., message: _Optional[str] = ..., traceback: _Optional[str] = ...) -> None: ...

View file

@ -0,0 +1,66 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/python.proto
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: v1/python.proto
# Protobuf Python Version: 5.29.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,
5,
29,
1,
'',
'v1/python.proto'
)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0fv1/python.proto\x12\x0e\x64jls.v1.python\"\x9c\x01\n\x06Python\x12\x1e\n\x02os\x18\x01 \x01(\x0b\x32\x12.djls.v1.python.Os\x12\"\n\x04site\x18\x02 \x01(\x0b\x32\x14.djls.v1.python.Site\x12 \n\x03sys\x18\x03 \x01(\x0b\x32\x13.djls.v1.python.Sys\x12,\n\tsysconfig\x18\x04 \x01(\x0b\x32\x19.djls.v1.python.Sysconfig\"f\n\x02Os\x12\x30\n\x07\x65nviron\x18\x01 \x03(\x0b\x32\x1f.djls.v1.python.Os.EnvironEntry\x1a.\n\x0c\x45nvironEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x86\x01\n\x04Site\x12\x34\n\x08packages\x18\x01 \x03(\x0b\x32\".djls.v1.python.Site.PackagesEntry\x1aH\n\rPackagesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.djls.v1.python.Package:\x02\x38\x01\"\xe0\x02\n\x03Sys\x12\x13\n\x0b\x64\x65\x62ug_build\x18\x01 \x01(\x08\x12\x10\n\x08\x64\x65v_mode\x18\x02 \x01(\x08\x12\x0f\n\x07is_venv\x18\x03 \x01(\x08\x12\x10\n\x08\x61\x62iflags\x18\x04 \x01(\t\x12\x13\n\x0b\x62\x61se_prefix\x18\x05 \x01(\t\x12\x18\n\x10\x64\x65\x66\x61ult_encoding\x18\x06 \x01(\t\x12\x12\n\nexecutable\x18\x07 \x01(\t\x12\x1b\n\x13\x66ilesystem_encoding\x18\x08 \x01(\t\x12\x1b\n\x13implementation_name\x18\t \x01(\t\x12\x10\n\x08platform\x18\n \x01(\t\x12\x0e\n\x06prefix\x18\x0b \x01(\t\x12\x1c\n\x14\x62uiltin_module_names\x18\x0c \x03(\t\x12\x11\n\tdll_paths\x18\r \x03(\t\x12\x0c\n\x04path\x18\x0e \x03(\t\x12\x31\n\x0cversion_info\x18\x0f \x01(\x0b\x32\x1b.djls.v1.python.VersionInfo\"~\n\x0bVersionInfo\x12\r\n\x05major\x18\x01 \x01(\r\x12\r\n\x05minor\x18\x02 \x01(\r\x12\r\n\x05micro\x18\x03 \x01(\r\x12\x32\n\x0creleaselevel\x18\x04 \x01(\x0e\x32\x1c.djls.v1.python.ReleaseLevel\x12\x0e\n\x06serial\x18\x05 \x01(\r\"\x96\x01\n\tSysconfig\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\x12\x0f\n\x07include\x18\x02 \x01(\t\x12\x13\n\x0bplatinclude\x18\x03 \x01(\t\x12\x0f\n\x07platlib\x18\x04 \x01(\t\x12\x12\n\nplatstdlib\x18\x05 \x01(\t\x12\x0f\n\x07purelib\x18\x06 \x01(\t\x12\x0f\n\x07scripts\x18\x07 \x01(\t\x12\x0e\n\x06stdlib\x18\x08 \x01(\t\"\x97\x02\n\x07Package\x12\x11\n\tdist_name\x18\x01 \x01(\t\x12\x14\n\x0c\x64ist_version\x18\x02 \x01(\t\x12\x1a\n\rdist_editable\x18\x03 \x01(\x08H\x00\x88\x01\x01\x12\x1e\n\x11\x64ist_entry_points\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rdist_location\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x15\n\rdist_requires\x18\x06 \x03(\t\x12!\n\x14\x64ist_requires_python\x18\x07 \x01(\tH\x03\x88\x01\x01\x42\x10\n\x0e_dist_editableB\x14\n\x12_dist_entry_pointsB\x10\n\x0e_dist_locationB\x17\n\x15_dist_requires_python\"\x17\n\x15GetEnvironmentRequest\"@\n\x16GetEnvironmentResponse\x12&\n\x06python\x18\x01 \x01(\x0b\x32\x16.djls.v1.python.Python*=\n\x0cReleaseLevel\x12\t\n\x05\x41LPHA\x10\x00\x12\x08\n\x04\x42\x45TA\x10\x01\x12\r\n\tCANDIDATE\x10\x02\x12\t\n\x05\x46INAL\x10\x03\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.python_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
DESCRIPTOR._loaded_options = None
_globals['_OS_ENVIRONENTRY']._loaded_options = None
_globals['_OS_ENVIRONENTRY']._serialized_options = b'8\001'
_globals['_SITE_PACKAGESENTRY']._loaded_options = None
_globals['_SITE_PACKAGESENTRY']._serialized_options = b'8\001'
_globals['_RELEASELEVEL']._serialized_start=1444
_globals['_RELEASELEVEL']._serialized_end=1505
_globals['_PYTHON']._serialized_start=36
_globals['_PYTHON']._serialized_end=192
_globals['_OS']._serialized_start=194
_globals['_OS']._serialized_end=296
_globals['_OS_ENVIRONENTRY']._serialized_start=250
_globals['_OS_ENVIRONENTRY']._serialized_end=296
_globals['_SITE']._serialized_start=299
_globals['_SITE']._serialized_end=433
_globals['_SITE_PACKAGESENTRY']._serialized_start=361
_globals['_SITE_PACKAGESENTRY']._serialized_end=433
_globals['_SYS']._serialized_start=436
_globals['_SYS']._serialized_end=788
_globals['_VERSIONINFO']._serialized_start=790
_globals['_VERSIONINFO']._serialized_end=916
_globals['_SYSCONFIG']._serialized_start=919
_globals['_SYSCONFIG']._serialized_end=1069
_globals['_PACKAGE']._serialized_start=1072
_globals['_PACKAGE']._serialized_end=1351
_globals['_GETENVIRONMENTREQUEST']._serialized_start=1353
_globals['_GETENVIRONMENTREQUEST']._serialized_end=1376
_globals['_GETENVIRONMENTRESPONSE']._serialized_start=1378
_globals['_GETENVIRONMENTRESPONSE']._serialized_end=1442
# @@protoc_insertion_point(module_scope)

View file

@ -0,0 +1,156 @@
# WARNING: This file is generated by protobuf. DO NOT EDIT!
# Any changes made to this file will be overwritten when the protobuf files are regenerated.
# Source: v1/python.proto
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
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 ReleaseLevel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
ALPHA: _ClassVar[ReleaseLevel]
BETA: _ClassVar[ReleaseLevel]
CANDIDATE: _ClassVar[ReleaseLevel]
FINAL: _ClassVar[ReleaseLevel]
ALPHA: ReleaseLevel
BETA: ReleaseLevel
CANDIDATE: ReleaseLevel
FINAL: ReleaseLevel
class Python(_message.Message):
__slots__ = ("os", "site", "sys", "sysconfig")
OS_FIELD_NUMBER: _ClassVar[int]
SITE_FIELD_NUMBER: _ClassVar[int]
SYS_FIELD_NUMBER: _ClassVar[int]
SYSCONFIG_FIELD_NUMBER: _ClassVar[int]
os: Os
site: Site
sys: Sys
sysconfig: Sysconfig
def __init__(self, os: _Optional[_Union[Os, _Mapping]] = ..., site: _Optional[_Union[Site, _Mapping]] = ..., sys: _Optional[_Union[Sys, _Mapping]] = ..., sysconfig: _Optional[_Union[Sysconfig, _Mapping]] = ...) -> None: ...
class Os(_message.Message):
__slots__ = ("environ",)
class EnvironEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: str
def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
ENVIRON_FIELD_NUMBER: _ClassVar[int]
environ: _containers.ScalarMap[str, str]
def __init__(self, environ: _Optional[_Mapping[str, str]] = ...) -> None: ...
class Site(_message.Message):
__slots__ = ("packages",)
class PackagesEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: Package
def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Package, _Mapping]] = ...) -> None: ...
PACKAGES_FIELD_NUMBER: _ClassVar[int]
packages: _containers.MessageMap[str, Package]
def __init__(self, packages: _Optional[_Mapping[str, Package]] = ...) -> None: ...
class Sys(_message.Message):
__slots__ = ("debug_build", "dev_mode", "is_venv", "abiflags", "base_prefix", "default_encoding", "executable", "filesystem_encoding", "implementation_name", "platform", "prefix", "builtin_module_names", "dll_paths", "path", "version_info")
DEBUG_BUILD_FIELD_NUMBER: _ClassVar[int]
DEV_MODE_FIELD_NUMBER: _ClassVar[int]
IS_VENV_FIELD_NUMBER: _ClassVar[int]
ABIFLAGS_FIELD_NUMBER: _ClassVar[int]
BASE_PREFIX_FIELD_NUMBER: _ClassVar[int]
DEFAULT_ENCODING_FIELD_NUMBER: _ClassVar[int]
EXECUTABLE_FIELD_NUMBER: _ClassVar[int]
FILESYSTEM_ENCODING_FIELD_NUMBER: _ClassVar[int]
IMPLEMENTATION_NAME_FIELD_NUMBER: _ClassVar[int]
PLATFORM_FIELD_NUMBER: _ClassVar[int]
PREFIX_FIELD_NUMBER: _ClassVar[int]
BUILTIN_MODULE_NAMES_FIELD_NUMBER: _ClassVar[int]
DLL_PATHS_FIELD_NUMBER: _ClassVar[int]
PATH_FIELD_NUMBER: _ClassVar[int]
VERSION_INFO_FIELD_NUMBER: _ClassVar[int]
debug_build: bool
dev_mode: bool
is_venv: bool
abiflags: str
base_prefix: str
default_encoding: str
executable: str
filesystem_encoding: str
implementation_name: str
platform: str
prefix: str
builtin_module_names: _containers.RepeatedScalarFieldContainer[str]
dll_paths: _containers.RepeatedScalarFieldContainer[str]
path: _containers.RepeatedScalarFieldContainer[str]
version_info: VersionInfo
def __init__(self, debug_build: bool = ..., dev_mode: bool = ..., is_venv: bool = ..., abiflags: _Optional[str] = ..., base_prefix: _Optional[str] = ..., default_encoding: _Optional[str] = ..., executable: _Optional[str] = ..., filesystem_encoding: _Optional[str] = ..., implementation_name: _Optional[str] = ..., platform: _Optional[str] = ..., prefix: _Optional[str] = ..., builtin_module_names: _Optional[_Iterable[str]] = ..., dll_paths: _Optional[_Iterable[str]] = ..., path: _Optional[_Iterable[str]] = ..., version_info: _Optional[_Union[VersionInfo, _Mapping]] = ...) -> None: ...
class VersionInfo(_message.Message):
__slots__ = ("major", "minor", "micro", "releaselevel", "serial")
MAJOR_FIELD_NUMBER: _ClassVar[int]
MINOR_FIELD_NUMBER: _ClassVar[int]
MICRO_FIELD_NUMBER: _ClassVar[int]
RELEASELEVEL_FIELD_NUMBER: _ClassVar[int]
SERIAL_FIELD_NUMBER: _ClassVar[int]
major: int
minor: int
micro: int
releaselevel: ReleaseLevel
serial: int
def __init__(self, major: _Optional[int] = ..., minor: _Optional[int] = ..., micro: _Optional[int] = ..., releaselevel: _Optional[_Union[ReleaseLevel, str]] = ..., serial: _Optional[int] = ...) -> None: ...
class Sysconfig(_message.Message):
__slots__ = ("data", "include", "platinclude", "platlib", "platstdlib", "purelib", "scripts", "stdlib")
DATA_FIELD_NUMBER: _ClassVar[int]
INCLUDE_FIELD_NUMBER: _ClassVar[int]
PLATINCLUDE_FIELD_NUMBER: _ClassVar[int]
PLATLIB_FIELD_NUMBER: _ClassVar[int]
PLATSTDLIB_FIELD_NUMBER: _ClassVar[int]
PURELIB_FIELD_NUMBER: _ClassVar[int]
SCRIPTS_FIELD_NUMBER: _ClassVar[int]
STDLIB_FIELD_NUMBER: _ClassVar[int]
data: str
include: str
platinclude: str
platlib: str
platstdlib: str
purelib: str
scripts: str
stdlib: str
def __init__(self, data: _Optional[str] = ..., include: _Optional[str] = ..., platinclude: _Optional[str] = ..., platlib: _Optional[str] = ..., platstdlib: _Optional[str] = ..., purelib: _Optional[str] = ..., scripts: _Optional[str] = ..., stdlib: _Optional[str] = ...) -> None: ...
class Package(_message.Message):
__slots__ = ("dist_name", "dist_version", "dist_editable", "dist_entry_points", "dist_location", "dist_requires", "dist_requires_python")
DIST_NAME_FIELD_NUMBER: _ClassVar[int]
DIST_VERSION_FIELD_NUMBER: _ClassVar[int]
DIST_EDITABLE_FIELD_NUMBER: _ClassVar[int]
DIST_ENTRY_POINTS_FIELD_NUMBER: _ClassVar[int]
DIST_LOCATION_FIELD_NUMBER: _ClassVar[int]
DIST_REQUIRES_FIELD_NUMBER: _ClassVar[int]
DIST_REQUIRES_PYTHON_FIELD_NUMBER: _ClassVar[int]
dist_name: str
dist_version: str
dist_editable: bool
dist_entry_points: str
dist_location: str
dist_requires: _containers.RepeatedScalarFieldContainer[str]
dist_requires_python: str
def __init__(self, dist_name: _Optional[str] = ..., dist_version: _Optional[str] = ..., dist_editable: bool = ..., dist_entry_points: _Optional[str] = ..., dist_location: _Optional[str] = ..., dist_requires: _Optional[_Iterable[str]] = ..., dist_requires_python: _Optional[str] = ...) -> None: ...
class GetEnvironmentRequest(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class GetEnvironmentResponse(_message.Message):
__slots__ = ("python",)
PYTHON_FIELD_NUMBER: _ClassVar[int]
python: Python
def __init__(self, python: _Optional[_Union[Python, _Mapping]] = ...) -> None: ...