Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions crates/djls-django/src/apps.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use djls_ipc::v1::*;
use djls_ipc::{ProcessError, PythonProcess};
use std::fmt;

#[derive(Debug)]
Expand Down Expand Up @@ -36,24 +34,6 @@ impl Apps {
pub fn iter(&self) -> impl Iterator<Item = &App> {
self.apps().iter()
}

pub fn check_installed(python: &mut PythonProcess, app: &str) -> Result<bool, ProcessError> {
let request = messages::Request {
command: Some(messages::request::Command::CheckAppInstalled(
check::AppInstalledRequest {
app_name: app.to_string(),
},
)),
};

let response = python.send(request).map_err(ProcessError::Transport)?;

match response.result {
Some(messages::response::Result::CheckAppInstalled(response)) => Ok(response.passed),
Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)),
_ => Err(ProcessError::Response),
}
}
}

impl fmt::Display for Apps {
Expand Down
29 changes: 17 additions & 12 deletions crates/djls-django/src/django.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::gis::{check_gis_setup, GISError};
use djls_ipc::v1::*;
use djls_ipc::IpcCommand;
use djls_ipc::{ProcessError, PythonProcess, TransportError};
Expand All @@ -24,16 +23,24 @@ impl DjangoProject {
pub fn setup(mut python: PythonProcess) -> Result<Self, ProjectError> {
let py = Python::setup(&mut python)?;

if !check_gis_setup(&mut python)? {
eprintln!("Warning: GeoDjango detected but GDAL is not available.");
eprintln!("Django initialization will be skipped. Some features may be limited.");
eprintln!("To enable full functionality, please install GDAL and other GeoDjango prerequisites.");
match check::GeoDjangoPrereqsRequest::execute(&mut python)?.result {
Some(messages::response::Result::CheckGeodjangoPrereqs(response)) => {
if !response.passed {
eprintln!("Warning: GeoDjango detected but GDAL is not available.");
eprintln!(
"Django initialization will be skipped. Some features may be limited."
);
eprintln!("To enable full functionality, please install GDAL and other GeoDjango prerequisites.");

return Ok(Self {
py,
python,
version: String::new(),
});
return Ok(Self {
py,
python,
version: String::new(),
});
}
}
Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message))?,
_ => Err(ProcessError::Response)?,
}

let response = django::GetProjectInfoRequest::execute(&mut python)?;
Expand Down Expand Up @@ -77,8 +84,6 @@ pub enum ProjectError {
DjangoNotFound,
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("GIS error: {0}")]
Gis(#[from] GISError),
#[error("JSON parsing error: {0}")]
Json(#[from] serde_json::Error),
#[error(transparent)]
Expand Down
26 changes: 0 additions & 26 deletions crates/djls-django/src/gis.rs

This file was deleted.

1 change: 0 additions & 1 deletion crates/djls-django/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
mod apps;
mod django;
mod gis;
mod templates;

pub use django::DjangoProject;
16 changes: 16 additions & 0 deletions crates/djls-ipc/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ impl IpcCommand for v1::check::HealthRequest {
}
}

impl IpcCommand for v1::check::GeoDjangoPrereqsRequest {
fn into_request(&self) -> messages::Request {
messages::Request {
command: Some(messages::request::Command::CheckGeodjangoPrereqs(*self)),
}
}

fn from_response(response: messages::Response) -> Result<messages::Response, ProcessError> {
match response.result {
Some(messages::response::Result::CheckGeodjangoPrereqs(_)) => Ok(response),
Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)),
_ => Err(ProcessError::Response),
}
}
}

impl IpcCommand for v1::python::GetEnvironmentRequest {
fn into_request(&self) -> messages::Request {
messages::Request {
Expand Down
6 changes: 2 additions & 4 deletions proto/v1/check.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ message HealthResponse {
optional string error = 2;
}

message AppInstalledRequest {
string app_name = 1;
}
message AppInstalledResponse {
message GeoDjangoPrereqsRequest {}
message GeoDjangoPrereqsResponse {
bool passed = 1;
optional string error = 2;
}
4 changes: 2 additions & 2 deletions proto/v1/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "v1/python.proto";
message Request {
oneof command {
check.HealthRequest check__health = 1;
check.AppInstalledRequest check__app_installed = 2;
check.GeoDjangoPrereqsRequest check__geodjango_prereqs = 2;
python.GetEnvironmentRequest python__get_environment = 1000;
django.GetProjectInfoRequest django__get_project_info = 2000;
}
Expand All @@ -18,7 +18,7 @@ message Request {
message Response {
oneof result {
check.HealthResponse check__health = 1;
check.AppInstalledResponse check__app_installed = 2;
check.GeoDjangoPrereqsResponse check__geodjango_prereqs = 2;
python.GetEnvironmentResponse python__get_environment = 1000;
django.GetProjectInfoResponse django__get_project_info = 2000;
Error error = 9000;
Expand Down
28 changes: 18 additions & 10 deletions python/djls/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import importlib.metadata
import inspect
import os
import subprocess
import sys
import sysconfig
import traceback
Expand Down Expand Up @@ -91,16 +92,23 @@ async def check__health(_request: check_pb2.HealthRequest) -> check_pb2.HealthRe
return check_pb2.HealthResponse(passed=True)


@proto_handler(
check_pb2.AppInstalledRequest,
error=messages_pb2.Error(
code=messages_pb2.Error.DJANGO_ERROR, message="App is not in INSTALLED_APPS"
),
)
async def check__app_installed(
request: check_pb2.AppInstalledRequest,
) -> check_pb2.AppInstalledResponse:
return check_pb2.AppInstalledResponse(passed=apps.is_installed(request.app_name))
@proto_handler(check_pb2.GeoDjangoPrereqsRequest)
async def check__geodjango_prereqs(
request: check_pb2.GeoDjangoPrereqsRequest,
) -> check_pb2.GeoDjangoPrereqsResponse:
has_geodjango = apps.is_installed("django.contrib.gis")

try:
gdal_process = subprocess.run(
["gdalinfo", "--version"], capture_output=True, check=False
)
gdal_is_installed = gdal_process.returncode == 0
except FileNotFoundError:
gdal_is_installed = False

return check_pb2.GeoDjangoPrereqsResponse(
passed=(not has_geodjango) or gdal_is_installed
)


@proto_handler(python_pb2.GetEnvironmentRequest)
Expand Down
10 changes: 5 additions & 5 deletions python/djls/proto/v1/check_pb2.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@



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\"\'\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')
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\"\x19\n\x17GeoDjangoPrereqsRequest\"H\n\x18GeoDjangoPrereqsResponse\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)
Expand All @@ -39,8 +39,8 @@
_globals['_HEALTHREQUEST']._serialized_end=48
_globals['_HEALTHRESPONSE']._serialized_start=50
_globals['_HEALTHRESPONSE']._serialized_end=112
_globals['_APPINSTALLEDREQUEST']._serialized_start=114
_globals['_APPINSTALLEDREQUEST']._serialized_end=153
_globals['_APPINSTALLEDRESPONSE']._serialized_start=155
_globals['_APPINSTALLEDRESPONSE']._serialized_end=223
_globals['_GEODJANGOPREREQSREQUEST']._serialized_start=114
_globals['_GEODJANGOPREREQSREQUEST']._serialized_end=139
_globals['_GEODJANGOPREREQSRESPONSE']._serialized_start=141
_globals['_GEODJANGOPREREQSRESPONSE']._serialized_end=213
# @@protoc_insertion_point(module_scope)
10 changes: 4 additions & 6 deletions python/djls/proto/v1/check_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ class HealthResponse(_message.Message):
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 GeoDjangoPrereqsRequest(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...

class AppInstalledResponse(_message.Message):
class GeoDjangoPrereqsResponse(_message.Message):
__slots__ = ("passed", "error")
PASSED_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
Expand Down
16 changes: 8 additions & 8 deletions python/djls/proto/v1/messages_pb2.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@
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\"\xa6\x02\n\x07Request\x12\x35\n\rcheck__health\x18\x01 \x01(\x0b\x32\x1c.djls.v1.check.HealthRequestH\x00\x12\x42\n\x14\x63heck__app_installed\x18\x02 \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\"\xd5\x02\n\x08Response\x12\x36\n\rcheck__health\x18\x01 \x01(\x0b\x32\x1d.djls.v1.check.HealthResponseH\x00\x12\x43\n\x14\x63heck__app_installed\x18\x02 \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')
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\"\xae\x02\n\x07Request\x12\x35\n\rcheck__health\x18\x01 \x01(\x0b\x32\x1c.djls.v1.check.HealthRequestH\x00\x12J\n\x18\x63heck__geodjango_prereqs\x18\x02 \x01(\x0b\x32&.djls.v1.check.GeoDjangoPrereqsRequestH\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\"\xdd\x02\n\x08Response\x12\x36\n\rcheck__health\x18\x01 \x01(\x0b\x32\x1d.djls.v1.check.HealthResponseH\x00\x12K\n\x18\x63heck__geodjango_prereqs\x18\x02 \x01(\x0b\x32\'.djls.v1.check.GeoDjangoPrereqsResponseH\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=384
_globals['_RESPONSE']._serialized_start=387
_globals['_RESPONSE']._serialized_end=728
_globals['_ERROR']._serialized_start=731
_globals['_ERROR']._serialized_end=896
_globals['_ERROR_CODE']._serialized_start=820
_globals['_ERROR_CODE']._serialized_end=896
_globals['_REQUEST']._serialized_end=392
_globals['_RESPONSE']._serialized_start=395
_globals['_RESPONSE']._serialized_end=744
_globals['_ERROR']._serialized_start=747
_globals['_ERROR']._serialized_end=912
_globals['_ERROR_CODE']._serialized_start=836
_globals['_ERROR_CODE']._serialized_end=912
# @@protoc_insertion_point(module_scope)
16 changes: 8 additions & 8 deletions python/djls/proto/v1/messages_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Opti
DESCRIPTOR: _descriptor.FileDescriptor

class Request(_message.Message):
__slots__ = ("check__health", "check__app_installed", "python__get_environment", "django__get_project_info")
__slots__ = ("check__health", "check__geodjango_prereqs", "python__get_environment", "django__get_project_info")
CHECK__HEALTH_FIELD_NUMBER: _ClassVar[int]
CHECK__APP_INSTALLED_FIELD_NUMBER: _ClassVar[int]
CHECK__GEODJANGO_PREREQS_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__app_installed: _check_pb2.AppInstalledRequest
check__geodjango_prereqs: _check_pb2.GeoDjangoPrereqsRequest
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__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: ...
def __init__(self, check__health: _Optional[_Union[_check_pb2.HealthRequest, _Mapping]] = ..., check__geodjango_prereqs: _Optional[_Union[_check_pb2.GeoDjangoPrereqsRequest, _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__app_installed", "python__get_environment", "django__get_project_info", "error")
__slots__ = ("check__health", "check__geodjango_prereqs", "python__get_environment", "django__get_project_info", "error")
CHECK__HEALTH_FIELD_NUMBER: _ClassVar[int]
CHECK__APP_INSTALLED_FIELD_NUMBER: _ClassVar[int]
CHECK__GEODJANGO_PREREQS_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__app_installed: _check_pb2.AppInstalledResponse
check__geodjango_prereqs: _check_pb2.GeoDjangoPrereqsResponse
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__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: ...
def __init__(self, check__health: _Optional[_Union[_check_pb2.HealthResponse, _Mapping]] = ..., check__geodjango_prereqs: _Optional[_Union[_check_pb2.GeoDjangoPrereqsResponse, _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")
Expand Down
Loading