mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:24 +00:00
Auto-generate environment variable references for ty (#19205)
## Summary
This PR mirrors the environment variable implementation we have in uv:
efc361223c/crates/uv-static/src/env_vars.rs (L6-L7)
.
See: https://github.com/astral-sh/ty/issues/773.
This commit is contained in:
parent
149350bf39
commit
3ee3434187
24 changed files with 458 additions and 14 deletions
|
@ -6,7 +6,7 @@ exclude: |
|
||||||
crates/ty_vendored/vendor/.*|
|
crates/ty_vendored/vendor/.*|
|
||||||
crates/ty_project/resources/.*|
|
crates/ty_project/resources/.*|
|
||||||
crates/ty_python_semantic/resources/corpus/.*|
|
crates/ty_python_semantic/resources/corpus/.*|
|
||||||
crates/ty/docs/(configuration|rules|cli).md|
|
crates/ty/docs/(configuration|rules|cli|environment).md|
|
||||||
crates/ruff_benchmark/resources/.*|
|
crates/ruff_benchmark/resources/.*|
|
||||||
crates/ruff_linter/resources/.*|
|
crates/ruff_linter/resources/.*|
|
||||||
crates/ruff_linter/src/rules/.*/snapshots/.*|
|
crates/ruff_linter/src/rules/.*/snapshots/.*|
|
||||||
|
|
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -2874,6 +2874,7 @@ dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"ty_static",
|
||||||
"web-time",
|
"web-time",
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
@ -2917,6 +2918,7 @@ dependencies = [
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"ty",
|
"ty",
|
||||||
"ty_project",
|
"ty_project",
|
||||||
|
"ty_static",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4165,6 +4167,7 @@ dependencies = [
|
||||||
"ty_project",
|
"ty_project",
|
||||||
"ty_python_semantic",
|
"ty_python_semantic",
|
||||||
"ty_server",
|
"ty_server",
|
||||||
|
"ty_static",
|
||||||
"wild",
|
"wild",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4186,6 +4189,15 @@ dependencies = [
|
||||||
"ty_vendored",
|
"ty_vendored",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ty_macros"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty_project"
|
name = "ty_project"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -4268,6 +4280,7 @@ dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tracing",
|
"tracing",
|
||||||
"ty_python_semantic",
|
"ty_python_semantic",
|
||||||
|
"ty_static",
|
||||||
"ty_test",
|
"ty_test",
|
||||||
"ty_vendored",
|
"ty_vendored",
|
||||||
]
|
]
|
||||||
|
@ -4299,6 +4312,13 @@ dependencies = [
|
||||||
"ty_vendored",
|
"ty_vendored",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ty_static"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"ty_macros",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty_test"
|
name = "ty_test"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -4327,6 +4347,7 @@ dependencies = [
|
||||||
"toml",
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
"ty_python_semantic",
|
"ty_python_semantic",
|
||||||
|
"ty_static",
|
||||||
"ty_vendored",
|
"ty_vendored",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,11 @@ ruff_workspace = { path = "crates/ruff_workspace" }
|
||||||
|
|
||||||
ty = { path = "crates/ty" }
|
ty = { path = "crates/ty" }
|
||||||
ty_ide = { path = "crates/ty_ide" }
|
ty_ide = { path = "crates/ty_ide" }
|
||||||
|
ty_macros = { path = "crates/ty_macros" }
|
||||||
ty_project = { path = "crates/ty_project", default-features = false }
|
ty_project = { path = "crates/ty_project", default-features = false }
|
||||||
ty_python_semantic = { path = "crates/ty_python_semantic" }
|
ty_python_semantic = { path = "crates/ty_python_semantic" }
|
||||||
ty_server = { path = "crates/ty_server" }
|
ty_server = { path = "crates/ty_server" }
|
||||||
|
ty_static = { path = "crates/ty_static" }
|
||||||
ty_test = { path = "crates/ty_test" }
|
ty_test = { path = "crates/ty_test" }
|
||||||
ty_vendored = { path = "crates/ty_vendored" }
|
ty_vendored = { path = "crates/ty_vendored" }
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ ruff_python_parser = { workspace = true }
|
||||||
ruff_python_trivia = { workspace = true }
|
ruff_python_trivia = { workspace = true }
|
||||||
ruff_source_file = { workspace = true, features = ["get-size"] }
|
ruff_source_file = { workspace = true, features = ["get-size"] }
|
||||||
ruff_text_size = { workspace = true }
|
ruff_text_size = { workspace = true }
|
||||||
|
ty_static = { workspace = true }
|
||||||
|
|
||||||
anstyle = { workspace = true }
|
anstyle = { workspace = true }
|
||||||
arc-swap = { workspace = true }
|
arc-swap = { workspace = true }
|
||||||
|
|
|
@ -5,6 +5,7 @@ use ruff_python_ast::PythonVersion;
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
use ty_static::EnvVars;
|
||||||
|
|
||||||
pub mod diagnostic;
|
pub mod diagnostic;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
|
@ -50,8 +51,8 @@ pub trait Db: salsa::Database {
|
||||||
/// ty can still spawn more threads for other tasks, e.g. to wait for a Ctrl+C signal or
|
/// ty can still spawn more threads for other tasks, e.g. to wait for a Ctrl+C signal or
|
||||||
/// watching the files for changes.
|
/// watching the files for changes.
|
||||||
pub fn max_parallelism() -> NonZeroUsize {
|
pub fn max_parallelism() -> NonZeroUsize {
|
||||||
std::env::var("TY_MAX_PARALLELISM")
|
std::env::var(EnvVars::TY_MAX_PARALLELISM)
|
||||||
.or_else(|_| std::env::var("RAYON_NUM_THREADS"))
|
.or_else(|_| std::env::var(EnvVars::RAYON_NUM_THREADS))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
|
|
|
@ -13,6 +13,7 @@ license = { workspace = true }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ty = { workspace = true }
|
ty = { workspace = true }
|
||||||
ty_project = { workspace = true, features = ["schemars"] }
|
ty_project = { workspace = true, features = ["schemars"] }
|
||||||
|
ty_static = { workspace = true }
|
||||||
ruff = { workspace = true }
|
ruff = { workspace = true }
|
||||||
ruff_formatter = { workspace = true }
|
ruff_formatter = { workspace = true }
|
||||||
ruff_linter = { workspace = true, features = ["schemars"] }
|
ruff_linter = { workspace = true, features = ["schemars"] }
|
||||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
generate_cli_help, generate_docs, generate_json_schema, generate_ty_cli_reference,
|
generate_cli_help, generate_docs, generate_json_schema, generate_ty_cli_reference,
|
||||||
generate_ty_options, generate_ty_rules, generate_ty_schema,
|
generate_ty_env_vars_reference, generate_ty_options, generate_ty_rules, generate_ty_schema,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) const REGENERATE_ALL_COMMAND: &str = "cargo dev generate-all";
|
pub(crate) const REGENERATE_ALL_COMMAND: &str = "cargo dev generate-all";
|
||||||
|
@ -44,5 +44,8 @@ pub(crate) fn main(args: &Args) -> Result<()> {
|
||||||
generate_ty_options::main(&generate_ty_options::Args { mode: args.mode })?;
|
generate_ty_options::main(&generate_ty_options::Args { mode: args.mode })?;
|
||||||
generate_ty_rules::main(&generate_ty_rules::Args { mode: args.mode })?;
|
generate_ty_rules::main(&generate_ty_rules::Args { mode: args.mode })?;
|
||||||
generate_ty_cli_reference::main(&generate_ty_cli_reference::Args { mode: args.mode })?;
|
generate_ty_cli_reference::main(&generate_ty_cli_reference::Args { mode: args.mode })?;
|
||||||
|
generate_ty_env_vars_reference::main(&generate_ty_env_vars_reference::Args {
|
||||||
|
mode: args.mode,
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
119
crates/ruff_dev/src/generate_ty_env_vars_reference.rs
Normal file
119
crates/ruff_dev/src/generate_ty_env_vars_reference.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
//! Generate the environment variables reference from `ty_static::EnvVars`.
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use anyhow::bail;
|
||||||
|
use pretty_assertions::StrComparison;
|
||||||
|
|
||||||
|
use ty_static::EnvVars;
|
||||||
|
|
||||||
|
use crate::generate_all::Mode;
|
||||||
|
|
||||||
|
#[derive(clap::Args)]
|
||||||
|
pub(crate) struct Args {
|
||||||
|
#[arg(long, default_value_t, value_enum)]
|
||||||
|
pub(crate) mode: Mode,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn main(args: &Args) -> anyhow::Result<()> {
|
||||||
|
let reference_string = generate();
|
||||||
|
let filename = "environment.md";
|
||||||
|
let reference_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.join("crates")
|
||||||
|
.join("ty")
|
||||||
|
.join("docs")
|
||||||
|
.join(filename);
|
||||||
|
|
||||||
|
match args.mode {
|
||||||
|
Mode::DryRun => {
|
||||||
|
println!("{reference_string}");
|
||||||
|
}
|
||||||
|
Mode::Check => match fs::read_to_string(&reference_path) {
|
||||||
|
Ok(current) => {
|
||||||
|
if current == reference_string {
|
||||||
|
println!("Up-to-date: {filename}");
|
||||||
|
} else {
|
||||||
|
let comparison = StrComparison::new(¤t, &reference_string);
|
||||||
|
bail!(
|
||||||
|
"{filename} changed, please run `cargo dev generate-ty-env-vars-reference`:\n{comparison}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||||
|
bail!(
|
||||||
|
"{filename} not found, please run `cargo dev generate-ty-env-vars-reference`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
bail!(
|
||||||
|
"{filename} changed, please run `cargo dev generate-ty-env-vars-reference`:\n{err}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Mode::Write => {
|
||||||
|
// Ensure the docs directory exists
|
||||||
|
if let Some(parent) = reference_path.parent() {
|
||||||
|
fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match fs::read_to_string(&reference_path) {
|
||||||
|
Ok(current) => {
|
||||||
|
if current == reference_string {
|
||||||
|
println!("Up-to-date: {filename}");
|
||||||
|
} else {
|
||||||
|
println!("Updating: {filename}");
|
||||||
|
fs::write(&reference_path, reference_string.as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||||
|
println!("Updating: {filename}");
|
||||||
|
fs::write(&reference_path, reference_string.as_bytes())?;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
bail!(
|
||||||
|
"{filename} changed, please run `cargo dev generate-ty-env-vars-reference`:\n{err}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate() -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
output.push_str("# Environment variables\n\n");
|
||||||
|
|
||||||
|
// Partition and sort environment variables into TY_ and external variables.
|
||||||
|
let (ty_vars, external_vars): (BTreeSet<_>, BTreeSet<_>) = EnvVars::metadata()
|
||||||
|
.iter()
|
||||||
|
.partition(|(var, _)| var.starts_with("TY_"));
|
||||||
|
|
||||||
|
output.push_str("ty defines and respects the following environment variables:\n\n");
|
||||||
|
|
||||||
|
for (var, doc) in ty_vars {
|
||||||
|
output.push_str(&render(var, doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str("## Externally-defined variables\n\n");
|
||||||
|
output.push_str("ty also reads the following externally defined environment variables:\n\n");
|
||||||
|
|
||||||
|
for (var, doc) in external_vars {
|
||||||
|
output.push_str(&render(var, doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render an environment variable and its documentation.
|
||||||
|
fn render(var: &str, doc: &str) -> String {
|
||||||
|
format!("### `{var}`\n\n{doc}\n\n")
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ mod generate_json_schema;
|
||||||
mod generate_options;
|
mod generate_options;
|
||||||
mod generate_rules_table;
|
mod generate_rules_table;
|
||||||
mod generate_ty_cli_reference;
|
mod generate_ty_cli_reference;
|
||||||
|
mod generate_ty_env_vars_reference;
|
||||||
mod generate_ty_options;
|
mod generate_ty_options;
|
||||||
mod generate_ty_rules;
|
mod generate_ty_rules;
|
||||||
mod generate_ty_schema;
|
mod generate_ty_schema;
|
||||||
|
@ -53,6 +54,8 @@ enum Command {
|
||||||
/// Generate a Markdown-compatible listing of configuration options.
|
/// Generate a Markdown-compatible listing of configuration options.
|
||||||
GenerateOptions,
|
GenerateOptions,
|
||||||
GenerateTyOptions(generate_ty_options::Args),
|
GenerateTyOptions(generate_ty_options::Args),
|
||||||
|
/// Generate environment variables reference for ty.
|
||||||
|
GenerateTyEnvVarsReference(generate_ty_env_vars_reference::Args),
|
||||||
/// Generate CLI help.
|
/// Generate CLI help.
|
||||||
GenerateCliHelp(generate_cli_help::Args),
|
GenerateCliHelp(generate_cli_help::Args),
|
||||||
/// Generate Markdown docs.
|
/// Generate Markdown docs.
|
||||||
|
@ -98,6 +101,7 @@ fn main() -> Result<ExitCode> {
|
||||||
Command::GenerateTyRules(args) => generate_ty_rules::main(&args)?,
|
Command::GenerateTyRules(args) => generate_ty_rules::main(&args)?,
|
||||||
Command::GenerateOptions => println!("{}", generate_options::generate()),
|
Command::GenerateOptions => println!("{}", generate_options::generate()),
|
||||||
Command::GenerateTyOptions(args) => generate_ty_options::main(&args)?,
|
Command::GenerateTyOptions(args) => generate_ty_options::main(&args)?,
|
||||||
|
Command::GenerateTyEnvVarsReference(args) => generate_ty_env_vars_reference::main(&args)?,
|
||||||
Command::GenerateCliHelp(args) => generate_cli_help::main(&args)?,
|
Command::GenerateCliHelp(args) => generate_cli_help::main(&args)?,
|
||||||
Command::GenerateDocs(args) => generate_docs::main(&args)?,
|
Command::GenerateDocs(args) => generate_docs::main(&args)?,
|
||||||
Command::PrintAST(args) => print_ast::main(&args)?,
|
Command::PrintAST(args) => print_ast::main(&args)?,
|
||||||
|
|
|
@ -19,6 +19,7 @@ ruff_python_ast = { workspace = true }
|
||||||
ty_python_semantic = { workspace = true }
|
ty_python_semantic = { workspace = true }
|
||||||
ty_project = { workspace = true, features = ["zstd"] }
|
ty_project = { workspace = true, features = ["zstd"] }
|
||||||
ty_server = { workspace = true }
|
ty_server = { workspace = true }
|
||||||
|
ty_static = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
argfile = { workspace = true }
|
argfile = { workspace = true }
|
||||||
|
|
55
crates/ty/docs/environment.md
Normal file
55
crates/ty/docs/environment.md
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# Environment variables
|
||||||
|
|
||||||
|
ty defines and respects the following environment variables:
|
||||||
|
|
||||||
|
### `TY_LOG`
|
||||||
|
|
||||||
|
If set, ty will use this value as the log level for its `--verbose` output.
|
||||||
|
Accepts any filter compatible with the `tracing_subscriber` crate.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
- `TY_LOG=uv=debug` is the equivalent of `-vv` to the command line
|
||||||
|
- `TY_LOG=trace` will enable all trace-level logging.
|
||||||
|
|
||||||
|
See the [tracing documentation](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax)
|
||||||
|
for more.
|
||||||
|
|
||||||
|
### `TY_LOG_PROFILE`
|
||||||
|
|
||||||
|
If set to `"1"` or `"true"`, ty will enable flamegraph profiling.
|
||||||
|
This creates a `tracing.folded` file that can be used to generate flame graphs
|
||||||
|
for performance analysis.
|
||||||
|
|
||||||
|
### `TY_MAX_PARALLELISM`
|
||||||
|
|
||||||
|
Specifies an upper limit for the number of tasks ty is allowed to run in parallel.
|
||||||
|
|
||||||
|
For example, how many files should be checked in parallel.
|
||||||
|
This isn't the same as a thread limit. ty may spawn additional threads
|
||||||
|
when necessary, e.g. to watch for file system changes or a dedicated UI thread.
|
||||||
|
|
||||||
|
## Externally-defined variables
|
||||||
|
|
||||||
|
ty also reads the following externally defined environment variables:
|
||||||
|
|
||||||
|
### `CONDA_PREFIX`
|
||||||
|
|
||||||
|
Used to detect an activated Conda environment location.
|
||||||
|
If both `VIRTUAL_ENV` and `CONDA_PREFIX` are present, `VIRTUAL_ENV` will be preferred.
|
||||||
|
|
||||||
|
### `RAYON_NUM_THREADS`
|
||||||
|
|
||||||
|
Specifies an upper limit for the number of threads ty uses when performing work in parallel.
|
||||||
|
Equivalent to `TY_MAX_PARALLELISM`.
|
||||||
|
|
||||||
|
This is a standard Rayon environment variable.
|
||||||
|
|
||||||
|
### `VIRTUAL_ENV`
|
||||||
|
|
||||||
|
Used to detect an activated virtual environment.
|
||||||
|
|
||||||
|
### `XDG_CONFIG_HOME`
|
||||||
|
|
||||||
|
Path to user-level configuration directory on Unix systems.
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod python_version;
|
||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
pub use args::Cli;
|
pub use args::Cli;
|
||||||
|
use ty_static::EnvVars;
|
||||||
|
|
||||||
use std::io::{self, BufWriter, Write, stdout};
|
use std::io::{self, BufWriter, Write, stdout};
|
||||||
use std::process::{ExitCode, Termination};
|
use std::process::{ExitCode, Termination};
|
||||||
|
@ -144,7 +145,7 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut stdout = stdout().lock();
|
let mut stdout = stdout().lock();
|
||||||
match std::env::var("TY_MEMORY_REPORT").as_deref() {
|
match std::env::var(EnvVars::TY_MEMORY_REPORT).as_deref() {
|
||||||
Ok("short") => write!(stdout, "{}", db.salsa_memory_dump().display_short())?,
|
Ok("short") => write!(stdout, "{}", db.salsa_memory_dump().display_short())?,
|
||||||
Ok("mypy_primer") => write!(stdout, "{}", db.salsa_memory_dump().display_mypy_primer())?,
|
Ok("mypy_primer") => write!(stdout, "{}", db.salsa_memory_dump().display_mypy_primer())?,
|
||||||
Ok("full") => write!(stdout, "{}", db.salsa_memory_dump().display_full())?,
|
Ok("full") => write!(stdout, "{}", db.salsa_memory_dump().display_full())?,
|
||||||
|
|
|
@ -12,6 +12,7 @@ use tracing_subscriber::filter::LevelFilter;
|
||||||
use tracing_subscriber::fmt::format::Writer;
|
use tracing_subscriber::fmt::format::Writer;
|
||||||
use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields};
|
use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields};
|
||||||
use tracing_subscriber::registry::LookupSpan;
|
use tracing_subscriber::registry::LookupSpan;
|
||||||
|
use ty_static::EnvVars;
|
||||||
|
|
||||||
/// Logging flags to `#[command(flatten)]` into your CLI
|
/// Logging flags to `#[command(flatten)]` into your CLI
|
||||||
#[derive(clap::Args, Debug, Clone, Default)]
|
#[derive(clap::Args, Debug, Clone, Default)]
|
||||||
|
@ -84,7 +85,7 @@ pub(crate) fn setup_tracing(
|
||||||
use tracing_subscriber::prelude::*;
|
use tracing_subscriber::prelude::*;
|
||||||
|
|
||||||
// The `TY_LOG` environment variable overrides the default log level.
|
// The `TY_LOG` environment variable overrides the default log level.
|
||||||
let filter = if let Ok(log_env_variable) = std::env::var("TY_LOG") {
|
let filter = if let Ok(log_env_variable) = std::env::var(EnvVars::TY_LOG) {
|
||||||
EnvFilter::builder()
|
EnvFilter::builder()
|
||||||
.parse(log_env_variable)
|
.parse(log_env_variable)
|
||||||
.context("Failed to parse directives specified in TY_LOG environment variable.")?
|
.context("Failed to parse directives specified in TY_LOG environment variable.")?
|
||||||
|
@ -165,7 +166,7 @@ fn setup_profile<S>() -> (
|
||||||
where
|
where
|
||||||
S: Subscriber + for<'span> LookupSpan<'span>,
|
S: Subscriber + for<'span> LookupSpan<'span>,
|
||||||
{
|
{
|
||||||
if let Ok("1" | "true") = std::env::var("TY_LOG_PROFILE").as_deref() {
|
if let Ok("1" | "true") = std::env::var(EnvVars::TY_LOG_PROFILE).as_deref() {
|
||||||
let (layer, guard) = tracing_flame::FlameLayer::with_file("tracing.folded")
|
let (layer, guard) = tracing_flame::FlameLayer::with_file("tracing.folded")
|
||||||
.expect("Flame layer to be created");
|
.expect("Flame layer to be created");
|
||||||
(Some(layer), Some(guard))
|
(Some(layer), Some(guard))
|
||||||
|
|
21
crates/ty_macros/Cargo.toml
Normal file
21
crates/ty_macros/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "ty_macros"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = { workspace = true }
|
||||||
|
rust-version = { workspace = true }
|
||||||
|
homepage = { workspace = true }
|
||||||
|
documentation = { workspace = true }
|
||||||
|
repository = { workspace = true }
|
||||||
|
authors = { workspace = true }
|
||||||
|
license = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = { workspace = true }
|
||||||
|
quote = { workspace = true }
|
||||||
|
syn = { workspace = true }
|
95
crates/ty_macros/src/env_vars.rs
Normal file
95
crates/ty_macros/src/env_vars.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{ImplItem, ItemImpl};
|
||||||
|
|
||||||
|
pub(crate) fn attribute_env_vars_metadata(mut input: ItemImpl) -> TokenStream {
|
||||||
|
// Verify that this is an impl for EnvVars
|
||||||
|
let impl_type = &input.self_ty;
|
||||||
|
|
||||||
|
let mut env_var_entries = Vec::new();
|
||||||
|
let mut hidden_vars = Vec::new();
|
||||||
|
|
||||||
|
// Process each item in the impl block
|
||||||
|
for item in &mut input.items {
|
||||||
|
if let ImplItem::Const(const_item) = item {
|
||||||
|
// Extract the const name and value
|
||||||
|
let const_name = &const_item.ident;
|
||||||
|
let const_expr = &const_item.expr;
|
||||||
|
|
||||||
|
// Check if the const has the #[attr_hidden] attribute
|
||||||
|
let is_hidden = const_item
|
||||||
|
.attrs
|
||||||
|
.iter()
|
||||||
|
.any(|attr| attr.path().is_ident("attr_hidden"));
|
||||||
|
|
||||||
|
// Remove our custom attributes
|
||||||
|
const_item.attrs.retain(|attr| {
|
||||||
|
!attr.path().is_ident("attr_hidden")
|
||||||
|
&& !attr.path().is_ident("attr_env_var_pattern")
|
||||||
|
});
|
||||||
|
|
||||||
|
if is_hidden {
|
||||||
|
hidden_vars.push(const_name.clone());
|
||||||
|
} else {
|
||||||
|
// Extract documentation from doc comments
|
||||||
|
let doc_attrs: Vec<_> = const_item
|
||||||
|
.attrs
|
||||||
|
.iter()
|
||||||
|
.filter(|attr| attr.path().is_ident("doc"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !doc_attrs.is_empty() {
|
||||||
|
// Convert doc attributes to a single string
|
||||||
|
let doc_string = extract_doc_string(&doc_attrs);
|
||||||
|
env_var_entries.push((const_name.clone(), const_expr.clone(), doc_string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the metadata method.
|
||||||
|
let metadata_entries: Vec<_> = env_var_entries
|
||||||
|
.iter()
|
||||||
|
.map(|(_name, expr, doc)| {
|
||||||
|
quote! {
|
||||||
|
(#expr, #doc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let metadata_impl = quote! {
|
||||||
|
impl #impl_type {
|
||||||
|
/// Returns metadata for all non-hidden environment variables.
|
||||||
|
pub fn metadata() -> Vec<(&'static str, &'static str)> {
|
||||||
|
vec![
|
||||||
|
#(#metadata_entries),*
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#input
|
||||||
|
#metadata_impl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract documentation from doc attributes into a single string
|
||||||
|
fn extract_doc_string(attrs: &[&syn::Attribute]) -> String {
|
||||||
|
attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|attr| {
|
||||||
|
if let syn::Meta::NameValue(meta) = &attr.meta {
|
||||||
|
if let syn::Expr::Lit(syn::ExprLit {
|
||||||
|
lit: syn::Lit::Str(lit_str),
|
||||||
|
..
|
||||||
|
}) = &meta.value
|
||||||
|
{
|
||||||
|
return Some(lit_str.value().trim().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
18
crates/ty_macros/src/lib.rs
Normal file
18
crates/ty_macros/src/lib.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
//! This crate implements internal macros for the `ty` library.
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use syn::parse_macro_input;
|
||||||
|
|
||||||
|
mod env_vars;
|
||||||
|
|
||||||
|
/// Generates metadata for environment variables declared in the impl block.
|
||||||
|
///
|
||||||
|
/// This attribute macro should be applied to an `impl EnvVars` block.
|
||||||
|
/// It will generate a `metadata()` method that returns all non-hidden
|
||||||
|
/// environment variables with their documentation.
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn attribute_env_vars_metadata(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(item as syn::ItemImpl);
|
||||||
|
|
||||||
|
env_vars::attribute_env_vars_metadata(input).into()
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ ruff_source_file = { workspace = true }
|
||||||
ruff_text_size = { workspace = true }
|
ruff_text_size = { workspace = true }
|
||||||
ruff_python_literal = { workspace = true }
|
ruff_python_literal = { workspace = true }
|
||||||
ruff_python_trivia = { workspace = true }
|
ruff_python_trivia = { workspace = true }
|
||||||
|
ty_static = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
bitflags = { workspace = true }
|
bitflags = { workspace = true }
|
||||||
|
@ -52,6 +53,7 @@ strum_macros = { workspace = true }
|
||||||
ruff_db = { workspace = true, features = ["testing", "os"] }
|
ruff_db = { workspace = true, features = ["testing", "os"] }
|
||||||
ruff_python_parser = { workspace = true }
|
ruff_python_parser = { workspace = true }
|
||||||
ty_python_semantic = { workspace = true, features = ["testing"] }
|
ty_python_semantic = { workspace = true, features = ["testing"] }
|
||||||
|
ty_static = { workspace = true }
|
||||||
ty_test = { workspace = true }
|
ty_test = { workspace = true }
|
||||||
ty_vendored = { workspace = true }
|
ty_vendored = { workspace = true }
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ use ruff_python_ast::PythonVersion;
|
||||||
use ruff_python_trivia::Cursor;
|
use ruff_python_trivia::Cursor;
|
||||||
use ruff_source_file::{LineIndex, OneIndexed, SourceCode};
|
use ruff_source_file::{LineIndex, OneIndexed, SourceCode};
|
||||||
use ruff_text_size::{TextLen, TextRange};
|
use ruff_text_size::{TextLen, TextRange};
|
||||||
|
use ty_static::EnvVars;
|
||||||
|
|
||||||
type SitePackagesDiscoveryResult<T> = Result<T, SitePackagesDiscoveryError>;
|
type SitePackagesDiscoveryResult<T> = Result<T, SitePackagesDiscoveryError>;
|
||||||
|
|
||||||
|
@ -149,7 +150,7 @@ impl PythonEnvironment {
|
||||||
PythonEnvironment::new(path, origin, system)
|
PythonEnvironment::new(path, origin, system)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(virtual_env) = system.env_var("VIRTUAL_ENV") {
|
if let Ok(virtual_env) = system.env_var(EnvVars::VIRTUAL_ENV) {
|
||||||
return resolve_environment(
|
return resolve_environment(
|
||||||
system,
|
system,
|
||||||
SystemPath::new(&virtual_env),
|
SystemPath::new(&virtual_env),
|
||||||
|
@ -158,7 +159,7 @@ impl PythonEnvironment {
|
||||||
.map(Some);
|
.map(Some);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(conda_env) = system.env_var("CONDA_PREFIX") {
|
if let Ok(conda_env) = system.env_var(EnvVars::CONDA_PREFIX) {
|
||||||
return resolve_environment(
|
return resolve_environment(
|
||||||
system,
|
system,
|
||||||
SystemPath::new(&conda_env),
|
SystemPath::new(&conda_env),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
use dir_test::{Fixture, dir_test};
|
use dir_test::{Fixture, dir_test};
|
||||||
|
use ty_static::EnvVars;
|
||||||
use ty_test::OutputFormat;
|
use ty_test::OutputFormat;
|
||||||
|
|
||||||
/// See `crates/ty_test/README.md` for documentation on these tests.
|
/// See `crates/ty_test/README.md` for documentation on these tests.
|
||||||
|
@ -19,7 +20,7 @@ fn mdtest(fixture: Fixture<&str>) {
|
||||||
|
|
||||||
let test_name = test_name("mdtest", absolute_fixture_path);
|
let test_name = test_name("mdtest", absolute_fixture_path);
|
||||||
|
|
||||||
let output_format = if std::env::var("MDTEST_GITHUB_ANNOTATIONS_FORMAT").is_ok() {
|
let output_format = if std::env::var(EnvVars::MDTEST_GITHUB_ANNOTATIONS_FORMAT).is_ok() {
|
||||||
OutputFormat::GitHub
|
OutputFormat::GitHub
|
||||||
} else {
|
} else {
|
||||||
OutputFormat::Cli
|
OutputFormat::Cli
|
||||||
|
|
19
crates/ty_static/Cargo.toml
Normal file
19
crates/ty_static/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "ty_static"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = { workspace = true }
|
||||||
|
rust-version = { workspace = true }
|
||||||
|
homepage = { workspace = true }
|
||||||
|
documentation = { workspace = true }
|
||||||
|
repository = { workspace = true }
|
||||||
|
authors = { workspace = true }
|
||||||
|
license = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ty_macros = { workspace = true }
|
71
crates/ty_static/src/env_vars.rs
Normal file
71
crates/ty_static/src/env_vars.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
use ty_macros::attribute_env_vars_metadata;
|
||||||
|
|
||||||
|
/// Declares all environment variable used throughout `ty` and its crates.
|
||||||
|
pub struct EnvVars;
|
||||||
|
|
||||||
|
#[attribute_env_vars_metadata]
|
||||||
|
impl EnvVars {
|
||||||
|
/// If set, ty will use this value as the log level for its `--verbose` output.
|
||||||
|
/// Accepts any filter compatible with the `tracing_subscriber` crate.
|
||||||
|
///
|
||||||
|
/// For example:
|
||||||
|
///
|
||||||
|
/// - `TY_LOG=uv=debug` is the equivalent of `-vv` to the command line
|
||||||
|
/// - `TY_LOG=trace` will enable all trace-level logging.
|
||||||
|
///
|
||||||
|
/// See the [tracing documentation](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax)
|
||||||
|
/// for more.
|
||||||
|
pub const TY_LOG: &'static str = "TY_LOG";
|
||||||
|
|
||||||
|
/// If set to `"1"` or `"true"`, ty will enable flamegraph profiling.
|
||||||
|
/// This creates a `tracing.folded` file that can be used to generate flame graphs
|
||||||
|
/// for performance analysis.
|
||||||
|
pub const TY_LOG_PROFILE: &'static str = "TY_LOG_PROFILE";
|
||||||
|
|
||||||
|
/// Control memory usage reporting format after ty execution.
|
||||||
|
///
|
||||||
|
/// Accepted values:
|
||||||
|
///
|
||||||
|
/// * `short` - Display short memory report
|
||||||
|
/// * `mypy_primer` - Display mypy_primer format and suppress workspace diagnostics
|
||||||
|
/// * `full` - Display full memory report
|
||||||
|
#[attr_hidden]
|
||||||
|
pub const TY_MEMORY_REPORT: &'static str = "TY_MEMORY_REPORT";
|
||||||
|
|
||||||
|
/// Specifies an upper limit for the number of tasks ty is allowed to run in parallel.
|
||||||
|
///
|
||||||
|
/// For example, how many files should be checked in parallel.
|
||||||
|
/// This isn't the same as a thread limit. ty may spawn additional threads
|
||||||
|
/// when necessary, e.g. to watch for file system changes or a dedicated UI thread.
|
||||||
|
pub const TY_MAX_PARALLELISM: &'static str = "TY_MAX_PARALLELISM";
|
||||||
|
|
||||||
|
/// Used to detect an activated virtual environment.
|
||||||
|
pub const VIRTUAL_ENV: &'static str = "VIRTUAL_ENV";
|
||||||
|
|
||||||
|
/// Used to detect an activated Conda environment location.
|
||||||
|
/// If both `VIRTUAL_ENV` and `CONDA_PREFIX` are present, `VIRTUAL_ENV` will be preferred.
|
||||||
|
pub const CONDA_PREFIX: &'static str = "CONDA_PREFIX";
|
||||||
|
|
||||||
|
/// Filter which tests to run in mdtest.
|
||||||
|
///
|
||||||
|
/// Only tests whose names contain this filter string will be executed.
|
||||||
|
#[attr_hidden]
|
||||||
|
pub const MDTEST_TEST_FILTER: &'static str = "MDTEST_TEST_FILTER";
|
||||||
|
|
||||||
|
/// Switch mdtest output format to GitHub Actions annotations.
|
||||||
|
///
|
||||||
|
/// If set (to any value), mdtest will output errors in GitHub Actions format.
|
||||||
|
#[attr_hidden]
|
||||||
|
pub const MDTEST_GITHUB_ANNOTATIONS_FORMAT: &'static str = "MDTEST_GITHUB_ANNOTATIONS_FORMAT";
|
||||||
|
|
||||||
|
// Externally defined environment variables
|
||||||
|
|
||||||
|
/// Specifies an upper limit for the number of threads ty uses when performing work in parallel.
|
||||||
|
/// Equivalent to `TY_MAX_PARALLELISM`.
|
||||||
|
///
|
||||||
|
/// This is a standard Rayon environment variable.
|
||||||
|
pub const RAYON_NUM_THREADS: &'static str = "RAYON_NUM_THREADS";
|
||||||
|
|
||||||
|
/// Path to user-level configuration directory on Unix systems.
|
||||||
|
pub const XDG_CONFIG_HOME: &'static str = "XDG_CONFIG_HOME";
|
||||||
|
}
|
3
crates/ty_static/src/lib.rs
Normal file
3
crates/ty_static/src/lib.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub use env_vars::*;
|
||||||
|
|
||||||
|
mod env_vars;
|
|
@ -19,6 +19,7 @@ ruff_source_file = { workspace = true }
|
||||||
ruff_text_size = { workspace = true }
|
ruff_text_size = { workspace = true }
|
||||||
ruff_python_ast = { workspace = true }
|
ruff_python_ast = { workspace = true }
|
||||||
ty_python_semantic = { workspace = true, features = ["serde", "testing"] }
|
ty_python_semantic = { workspace = true, features = ["serde", "testing"] }
|
||||||
|
ty_static = { workspace = true }
|
||||||
ty_vendored = { workspace = true }
|
ty_vendored = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|
|
@ -29,7 +29,7 @@ mod diagnostic;
|
||||||
mod matcher;
|
mod matcher;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
const MDTEST_TEST_FILTER: &str = "MDTEST_TEST_FILTER";
|
use ty_static::EnvVars;
|
||||||
|
|
||||||
/// Run `path` as a markdown test suite with given `title`.
|
/// Run `path` as a markdown test suite with given `title`.
|
||||||
///
|
///
|
||||||
|
@ -53,7 +53,7 @@ pub fn run(
|
||||||
|
|
||||||
let mut db = db::Db::setup();
|
let mut db = db::Db::setup();
|
||||||
|
|
||||||
let filter = std::env::var(MDTEST_TEST_FILTER).ok();
|
let filter = std::env::var(EnvVars::MDTEST_TEST_FILTER).ok();
|
||||||
let mut any_failures = false;
|
let mut any_failures = false;
|
||||||
for test in suite.tests() {
|
for test in suite.tests() {
|
||||||
if filter
|
if filter
|
||||||
|
@ -105,10 +105,12 @@ pub fn run(
|
||||||
|
|
||||||
if output_format.is_cli() {
|
if output_format.is_cli() {
|
||||||
println!(
|
println!(
|
||||||
"\nTo rerun this specific test, set the environment variable: {MDTEST_TEST_FILTER}='{escaped_test_name}'",
|
"\nTo rerun this specific test, set the environment variable: {}='{escaped_test_name}'",
|
||||||
|
EnvVars::MDTEST_TEST_FILTER,
|
||||||
);
|
);
|
||||||
println!(
|
println!(
|
||||||
"{MDTEST_TEST_FILTER}='{escaped_test_name}' cargo test -p ty_python_semantic --test mdtest -- {test_name}",
|
"{}='{escaped_test_name}' cargo test -p ty_python_semantic --test mdtest -- {test_name}",
|
||||||
|
EnvVars::MDTEST_TEST_FILTER,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue