Skip to content

Commit

Permalink
feat: python version override - pyright as checker (#94)
Browse files Browse the repository at this point in the history
* feat: python version override - pyright as checker

* chore: fix img background remover test

* chore: fix img background remover test

* chore: adapted test for local windows

* chore: fixed borrowed dep
  • Loading branch information
agallardol authored Jan 22, 2025
1 parent 0b7347b commit 644457a
Show file tree
Hide file tree
Showing 4 changed files with 361 additions and 8 deletions.
8 changes: 7 additions & 1 deletion docker-images/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
FROM denoland/deno:debian-2.1.1

SHELL ["/bin/bash", "-c"]

# This is a workaround to get playwright to install so we can use stagehand
RUN deno init dummy-project
WORKDIR /dummy-project
RUN deno add --allow-scripts npm:@playwright/test@1.42.1 && deno run -A npm:playwright install
# Add chromium
RUN apt-get update && apt-get install -y chromium
ENV CHROME_PATH=/usr/bin/chromium
Expand All @@ -15,4 +18,7 @@ ENV PATH="/root/.local/bin:${PATH}"

RUN source $HOME/.local/bin/env && uv venv --seed cache/python-venv --python 3.13 && source cache/python-venv/bin/activate && uv pip install pipreqs && uv tool install ruff

RUN ls $HOME/.cache/ms-playwright


ENTRYPOINT ["/tini", "--"]
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ impl ExecutionStorage {
pub fn python_cache_folder_path(&self) -> std::path::PathBuf {
self.cache_folder_path.join("python-venv")
}
pub fn python_check_venv_folder_path(&self) -> std::path::PathBuf {
self.cache_folder_path.join("python-check-venv")
}
pub fn init_for_python(&self, pristine_cache: Option<bool>) -> anyhow::Result<()> {
self.init(pristine_cache)?;

log::info!("creating python cache directory");
let deno_cache_dir = self.python_cache_folder_path();
std::fs::create_dir_all(&deno_cache_dir).map_err(|e| {
let python_cache_dir = self.python_cache_folder_path();
std::fs::create_dir_all(&python_cache_dir).map_err(|e| {
log::error!("failed to create deno cache directory: {}", e);
e
})?;
Expand Down
136 changes: 131 additions & 5 deletions libs/shinkai-tools-runner/src/tools/python_runner.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use serde_json::Value;
use std::{
collections::HashMap,
ops::{Deref, DerefMut},
path::{self, Path, PathBuf},
sync::Arc,
time::Duration,
Expand Down Expand Up @@ -74,6 +75,41 @@ impl PythonRunner {
Ok(())
}

async fn ensure_pyright(&self, venv_path: PathBuf) -> anyhow::Result<()> {
let uv_binary_path = path::absolute(self.options.uv_binary_path.clone())
.unwrap()
.to_str()
.unwrap()
.to_string();

let mut install_ruff_command = tokio::process::Command::new(uv_binary_path);
let install_ruff_command = install_ruff_command
.args(["pip", "install", "pyright"])
.env(
"VIRTUAL_ENV",
venv_path.to_string_lossy().to_string().as_str(),
)
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.kill_on_drop(true);

log::info!("Installing pyright...");
let install_output = install_ruff_command
.spawn()?
.wait_with_output()
.await
.map_err(|e| anyhow::anyhow!("failed to install pyright: {}", e))?;

if !install_output.status.success() {
let stderr = String::from_utf8_lossy(&install_output.stderr);
log::error!("failed to install pyright: {}", stderr);
return Err(anyhow::anyhow!("failed to install pyright: {}", stderr));
}

log::info!("pyright installed successfully.");
Ok(())
}

pub fn extend_with_pyproject_toml(code_files: CodeFiles) -> anyhow::Result<CodeFiles> {
let mut code_files = code_files.clone();
let code_entrypoint = match code_files.files.get(&code_files.entrypoint.clone()) {
Expand Down Expand Up @@ -148,6 +184,15 @@ requires-python = ">=3.13"
}
}
}
if let Some(python_version) = pyproject_toml_from_code_endpoint.get("requires-python") {
if let Some(project) = pyproject_toml.get_mut("project") {
project
.as_table_mut()
.unwrap()
.insert("requires-python", python_version.clone());
log::info!("overridingpython version: {}", python_version);
}
}
log::info!(
"autogenerated pyproject_toml: {}",
pyproject_toml.to_string()
Expand All @@ -164,10 +209,36 @@ requires-python = ">=3.13"
ExecutionStorage::new(self.code.clone(), self.options.context.clone());
execution_storage.init_for_python(None)?;

let uv_binary_path = path::absolute(self.options.uv_binary_path.clone())
.unwrap()
.to_str()
.unwrap()
.to_string();

let mut create_check_venv_command = tokio::process::Command::new(uv_binary_path);
let command = create_check_venv_command
.args([
"venv",
execution_storage
.python_check_venv_folder_path()
.to_string_lossy()
.to_string()
.as_str(),
])
.kill_on_drop(true);
match command.spawn() {
Ok(child) => child.wait_with_output().await?,
Err(e) => {
log::error!("failed to spawn command: {}", e);
return Err(anyhow::anyhow!("failed to spawn uv venv command: {}", e));
}
};

self.ensure_ruff().await?;
self.ensure_pyright(execution_storage.python_check_venv_folder_path())
.await?;

log::info!("Starting code check with ruff...");

let mut command = tokio::process::Command::new("ruff");
command
.args(["check"])
Expand All @@ -184,15 +255,70 @@ requires-python = ">=3.13"
};

let lint_message = String::from_utf8(output.stdout)?;
let lint_message_lines: Vec<String> =
lint_message.lines().map(|s| s.to_string()).collect();

let lint_message_lines: Vec<String> = lint_message.lines().map(|s| s.to_string()).collect();

for line in &lint_message_lines {
log::info!("python check message: {}", line);
log::info!("python ruff lint message: {}", line);
}

// When success, ruff returns 1 line with "All check passed!"
if lint_message_lines.len() > 1 {
return Ok(lint_message_lines);
}

log::info!("starting pyright check");
let mut command = tokio::process::Command::new("uv");
command
.args([
"run",
"-m",
"pyright",
"--level=error",
execution_storage
.code_entrypoint_file_path
.to_string_lossy()
.to_string()
.as_str(),
])
.env(
"VIRTUAL_ENV",
execution_storage
.python_check_venv_folder_path()
.to_string_lossy()
.to_string()
.as_str(),
)
.current_dir(execution_storage.code_folder_path.clone())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.kill_on_drop(true);
let output = match command.spawn() {
Ok(child) => match child.wait_with_output().await {
Ok(output) => output,
Err(e) => {
log::error!("failed to get command output: {}", e);
return Err(anyhow::anyhow!(
"failed to get pyright command output: {}",
e
));
}
},
Err(e) => {
log::error!("failed to spawn command: {}", e);
return Err(anyhow::anyhow!("failed to spawn pyright command: {}", e));
}
};
log::info!("pyright check finished");

let lint_message = String::from_utf8(output.stdout)?;
let lint_message_lines: Vec<String> = lint_message.lines().map(|s| s.to_string()).collect();

for line in &lint_message_lines {
log::info!("python pyright check message: {}", line);
}
// When success, pyright returns 1 line with "0 errors, 0 warnings, 0 informations"
if lint_message_lines.len() <= 1 {
log::info!("pyright check passed");
return Ok(vec![]);
}

Expand Down
Loading

0 comments on commit 644457a

Please sign in to comment.