Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: python version override - pyright as checker #94

Merged
merged 5 commits into from
Jan 22, 2025
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
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/[email protected] && 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},

Check warning on line 4 in libs/shinkai-tools-runner/src/tools/python_runner.rs

View workflow job for this annotation

GitHub Actions / check

unused imports: `DerefMut`, `Deref`, and `Path`

Check warning on line 4 in libs/shinkai-tools-runner/src/tools/python_runner.rs

View workflow job for this annotation

GitHub Actions / check

unused imports: `DerefMut`, `Deref`, and `Path`

Check warning on line 4 in libs/shinkai-tools-runner/src/tools/python_runner.rs

View workflow job for this annotation

GitHub Actions / check

unused imports: `DerefMut`, `Deref`, and `Path`

Check warning on line 4 in libs/shinkai-tools-runner/src/tools/python_runner.rs

View workflow job for this annotation

GitHub Actions / check

unused imports: `DerefMut`, `Deref`, and `Path`
path::{self, Path, PathBuf},
sync::Arc,
time::Duration,
Expand Down Expand Up @@ -74,6 +75,41 @@
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 @@
}
}
}
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 @@
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 @@
};

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
Loading