drop environment abstraction layer over Python interpreter (#5)

This commit is contained in:
Josh Thomas 2024-12-06 09:45:36 -06:00 committed by GitHub
parent 39523d1f89
commit b7a1de98dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 17 additions and 66 deletions

View file

@ -1,53 +0,0 @@
use crate::python::{Interpreter, PythonError};
use std::fmt;
use std::path::PathBuf;
use which::which;
#[derive(Debug)]
pub struct PythonEnvironment {
root: PathBuf,
py: Interpreter,
}
impl PythonEnvironment {
fn new(root: PathBuf, py: Interpreter) -> Self {
Self { root, py }
}
pub fn initialize() -> Result<Self, EnvironmentError> {
let executable = which("python")?;
let py = Interpreter::from_sys_executable(&executable)?;
let root = py.sys_prefix().clone();
Ok(Self::new(root, py))
}
pub fn root(&self) -> &PathBuf {
&self.root
}
pub fn py(&self) -> &Interpreter {
&self.py
}
}
impl fmt::Display for PythonEnvironment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Python Environment")?;
writeln!(f, "Root: {}", self.root.display())?;
writeln!(f)?;
writeln!(f, "Interpreter")?;
writeln!(f, "{}", self.py)
}
}
#[derive(Debug, thiserror::Error)]
pub enum EnvironmentError {
#[error("Failed to locate Python executable: {0}")]
PythonNotFound(#[from] which::Error),
#[error("Runtime error: {0}")]
Runtime(#[from] PythonError),
#[error("Environment initialization failed: {0}")]
Init(String),
}

View file

@ -1,5 +1,4 @@
mod environment;
mod packaging; mod packaging;
mod python; mod python;
pub use environment::PythonEnvironment; pub use python::Python;

View file

@ -3,6 +3,7 @@ use serde::Deserialize;
use std::fmt; use std::fmt;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use which::which;
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
pub struct VersionInfo { pub struct VersionInfo {
@ -101,7 +102,7 @@ impl fmt::Display for SysconfigPaths {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Interpreter { pub struct Python {
version_info: VersionInfo, version_info: VersionInfo,
sysconfig_paths: SysconfigPaths, sysconfig_paths: SysconfigPaths,
sys_prefix: PathBuf, sys_prefix: PathBuf,
@ -111,7 +112,7 @@ pub struct Interpreter {
packages: Packages, packages: Packages,
} }
impl Interpreter { impl Python {
fn new( fn new(
version_info: VersionInfo, version_info: VersionInfo,
sysconfig_paths: SysconfigPaths, sysconfig_paths: SysconfigPaths,
@ -132,8 +133,9 @@ impl Interpreter {
} }
} }
pub fn from_sys_executable(executable: &PathBuf) -> Result<Self, PythonError> { pub fn initialize() -> Result<Self, PythonError> {
let output = Command::new(executable) let executable = which("python")?;
let output = Command::new(&executable)
.args([ .args([
"-c", "-c",
r#" r#"
@ -152,8 +154,8 @@ print(json.dumps({
let sys_info: serde_json::Value = serde_json::from_str(&output_str)?; let sys_info: serde_json::Value = serde_json::from_str(&output_str)?;
Ok(Self::new( Ok(Self::new(
VersionInfo::from_executable(executable)?, VersionInfo::from_executable(&executable)?,
SysconfigPaths::from_executable(executable)?, SysconfigPaths::from_executable(&executable)?,
PathBuf::from(sys_info["prefix"].as_str().unwrap()), PathBuf::from(sys_info["prefix"].as_str().unwrap()),
PathBuf::from(sys_info["base_prefix"].as_str().unwrap()), PathBuf::from(sys_info["base_prefix"].as_str().unwrap()),
PathBuf::from(sys_info["executable"].as_str().unwrap()), PathBuf::from(sys_info["executable"].as_str().unwrap()),
@ -163,7 +165,7 @@ print(json.dumps({
.iter() .iter()
.map(|p| PathBuf::from(p.as_str().unwrap())) .map(|p| PathBuf::from(p.as_str().unwrap()))
.collect(), .collect(),
Packages::from_executable(executable)?, Packages::from_executable(&executable)?,
)) ))
} }
@ -230,7 +232,7 @@ print(json.dumps({
} }
} }
impl fmt::Display for Interpreter { impl fmt::Display for Python {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Version: {}", self.version_info)?; writeln!(f, "Version: {}", self.version_info)?;
writeln!(f, "Executable: {}", self.sys_executable.display())?; writeln!(f, "Executable: {}", self.sys_executable.display())?;
@ -249,6 +251,9 @@ impl fmt::Display for Interpreter {
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum PythonError { pub enum PythonError {
#[error("Failed to locate Python executable: {0}")]
PythonNotFound(#[from] which::Error),
#[error("IO error: {0}")] #[error("IO error: {0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),

View file

@ -3,12 +3,12 @@ use tower_lsp::jsonrpc::Result as LspResult;
use tower_lsp::lsp_types::*; use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer, LspService, Server}; use tower_lsp::{Client, LanguageServer, LspService, Server};
use djls_python::PythonEnvironment; use djls_python::Python;
#[derive(Debug)] #[derive(Debug)]
struct Backend { struct Backend {
client: Client, client: Client,
python: PythonEnvironment, python: Python,
} }
#[tower_lsp::async_trait] #[tower_lsp::async_trait]
@ -46,7 +46,7 @@ impl LanguageServer for Backend {
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let python = PythonEnvironment::initialize()?; let python = Python::initialize()?;
let stdin = tokio::io::stdin(); let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout(); let stdout = tokio::io::stdout();