abstract zipapp to separate dedicated submodule (#215)
Some checks are pending
test / Python , Django () (push) Blocked by required conditions
lint / pre-commit (push) Waiting to run
lint / rustfmt (push) Waiting to run
lint / clippy (push) Waiting to run
lint / cargo-check (push) Waiting to run
release / build (push) Waiting to run
release / test (push) Waiting to run
release / release (push) Blocked by required conditions
test / generate-matrix (push) Waiting to run
test / tests (push) Blocked by required conditions
zizmor 🌈 / zizmor latest via PyPI (push) Waiting to run

This commit is contained in:
Josh Thomas 2025-09-10 09:41:00 -05:00 committed by GitHub
parent d99c96d6b6
commit 007a009d33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 64 additions and 57 deletions

View file

@ -1,6 +1,7 @@
pub mod ipc;
pub mod pool;
pub mod queries;
mod zipapp;
pub use queries::Query;
use serde::Deserialize;

View file

@ -9,43 +9,25 @@ use std::process::Stdio;
use anyhow::Context;
use anyhow::Result;
use serde_json;
use tempfile::NamedTempFile;
use super::zipapp::InspectorFile;
use super::DjlsRequest;
use super::DjlsResponse;
use crate::python::PythonEnvironment;
const INSPECTOR_PYZ: &[u8] = include_bytes!(concat!(
env!("CARGO_WORKSPACE_DIR"),
"/python/dist/djls_inspector.pyz"
));
pub struct InspectorProcess {
child: Child,
stdin: std::process::ChildStdin,
stdout: BufReader<std::process::ChildStdout>,
_zipapp_file: NamedTempFile,
_zipapp_file: InspectorFile,
}
impl InspectorProcess {
pub fn new(python_env: &PythonEnvironment, project_path: &Path) -> Result<Self> {
let mut zipapp_file = tempfile::Builder::new()
.prefix("djls_inspector_")
.suffix(".pyz")
.tempfile()
.context("Failed to create temp file for inspector")?;
zipapp_file
.write_all(INSPECTOR_PYZ)
.context("Failed to write inspector zipapp to temp file")?;
zipapp_file
.flush()
.context("Failed to flush inspector zipapp")?;
let zipapp_path = zipapp_file.path();
let zipapp_file = InspectorFile::create()?;
let mut cmd = Command::new(&python_env.python_path);
cmd.arg(zipapp_path)
cmd.arg(zipapp_file.path())
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())

View file

@ -12,15 +12,6 @@ pub enum Query {
DjangoInit,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum VersionReleaseLevel {
Alpha,
Beta,
Candidate,
Final,
}
#[derive(Serialize, Deserialize)]
pub struct PythonEnvironmentQueryData {
pub sys_base_prefix: PathBuf,
@ -31,6 +22,15 @@ pub struct PythonEnvironmentQueryData {
pub sys_version_info: (u32, u32, u32, VersionReleaseLevel, u32),
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum VersionReleaseLevel {
Alpha,
Beta,
Candidate,
Final,
}
#[derive(Serialize, Deserialize)]
pub struct TemplateTagQueryData {
pub templatetags: Vec<TemplateTag>,
@ -42,9 +42,3 @@ pub struct TemplateTag {
pub module: String,
pub doc: Option<String>,
}
#[derive(Serialize, Deserialize)]
pub struct DjangoInitQueryData {
pub success: bool,
pub message: Option<String>,
}

View file

@ -0,0 +1,36 @@
use std::io::Write;
use std::path::Path;
use anyhow::Context;
use anyhow::Result;
use tempfile::NamedTempFile;
const INSPECTOR_PYZ: &[u8] = include_bytes!(concat!(
env!("CARGO_WORKSPACE_DIR"),
"/python/dist/djls_inspector.pyz"
));
pub struct InspectorFile(NamedTempFile);
impl InspectorFile {
pub fn create() -> Result<Self> {
let mut zipapp_file = tempfile::Builder::new()
.prefix("djls_inspector_")
.suffix(".pyz")
.tempfile()
.context("Failed to create temp file for inspector")?;
zipapp_file
.write_all(INSPECTOR_PYZ)
.context("Failed to write inspector zipapp to temp file")?;
zipapp_file
.flush()
.context("Failed to flush inspector zipapp")?;
Ok(Self(zipapp_file))
}
pub fn path(&self) -> &Path {
self.0.path()
}
}

View file

@ -26,7 +26,7 @@ pub struct DjangoProject {
path: PathBuf,
env: Option<PythonEnvironment>,
template_tags: Option<TemplateTags>,
inspector_pool: Arc<InspectorPool>,
inspector: Arc<InspectorPool>,
}
impl DjangoProject {
@ -36,7 +36,7 @@ impl DjangoProject {
path,
env: None,
template_tags: None,
inspector_pool: Arc::new(InspectorPool::new()),
inspector: Arc::new(InspectorPool::new()),
}
}
@ -52,7 +52,7 @@ impl DjangoProject {
let request = DjlsRequest {
query: Query::DjangoInit,
};
let response = self.inspector_pool.query(env, &self.path, &request)?;
let response = self.inspector.query(env, &self.path, &request)?;
if !response.ok {
anyhow::bail!("Failed to initialize Django: {:?}", response.error);
@ -62,7 +62,7 @@ impl DjangoProject {
let request = DjlsRequest {
query: Query::Templatetags,
};
let response = self.inspector_pool.query(env, &self.path, &request)?;
let response = self.inspector.query(env, &self.path, &request)?;
if let Some(data) = response.data {
self.template_tags = Some(TemplateTags::from_json(&data)?);

View file

@ -69,7 +69,8 @@ def handle_request(request: dict[str, Any]) -> DjlsResponse:
return DjlsResponse(ok=True, data=get_installed_templatetags())
elif query == Query.DJANGO_INIT:
return DjlsResponse(ok=True, data=initialize_django())
success, error = initialize_django()
return DjlsResponse(ok=success, data=None, error=error)
return DjlsResponse(ok=False, error=f"Unhandled query type: {query}")

View file

@ -90,13 +90,8 @@ def get_installed_templatetags() -> TemplateTagQueryData:
return TemplateTagQueryData(templatetags=templatetags)
@dataclass
class DjangoInitQueryData:
success: bool
message: str | None = None
def initialize_django() -> DjangoInitQueryData:
def initialize_django() -> tuple[bool, str | None]:
"""Initialize Django and return (success, error_message)."""
import os
import django
from django.apps import apps
@ -122,9 +117,9 @@ def initialize_django() -> DjangoInitQueryData:
current_path = current_path.parent
if not manage_py:
return DjangoInitQueryData(
success=False,
message="Could not find manage.py or DJANGO_SETTINGS_MODULE not set",
return (
False,
"Could not find manage.py or DJANGO_SETTINGS_MODULE not set",
)
# Add project directory to sys.path
@ -163,12 +158,10 @@ def initialize_django() -> DjangoInitQueryData:
if not apps.ready:
django.setup()
return DjangoInitQueryData(
success=True, message="Django initialized successfully"
)
return True, None
except Exception as e:
return DjangoInitQueryData(success=False, message=str(e))
return False, str(e)
QueryData = PythonEnvironmentQueryData | TemplateTagQueryData | DjangoInitQueryData
QueryData = PythonEnvironmentQueryData | TemplateTagQueryData