Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
5f00505
drop from uv.lock the five zensical 0.0.57 wheels pypi no longer serv…
KotlinIsland Oct 29, 2026
9e252ac
widen a kind of literal that keeps growing from one round of a cycle …
KotlinIsland Oct 26, 2026
6b3dc35
find a decorated override as the def it is, not as the function its d…
KotlinIsland Oct 26, 2026
8cee3ba
give a type that mentions Unknown no annotation, so add return annota…
KotlinIsland Oct 26, 2026
c392cdd
complete a callable that takes no arguments as its whole call, with t…
KotlinIsland Oct 26, 2026
245887a
fold a docstring once, as the documentation range, not a second time …
KotlinIsland Oct 26, 2026
8a8e867
give folding ranges basedpython's own kinds — docstring, function, cl…
KotlinIsland Oct 26, 2026
a15d155
mark builtins defaultLibrary, every token of a type expression annota…
KotlinIsland Oct 26, 2026
227a8fc
put a pytest plugin in the tree by run stages, which moves the functi…
KotlinIsland Oct 26, 2026
8403fbc
go to the constructor a class's call runs from the class's name, as o…
KotlinIsland Oct 26, 2026
1825f4c
extend a selection through an element with its comma, a list's elemen…
KotlinIsland Oct 26, 2026
2d5d0d6
open a hover with the hovered name's kind and qualified name, method …
KotlinIsland Oct 26, 2026
ec39c70
answer by/declaration, the kind, name and qualified name of what the …
KotlinIsland Oct 26, 2026
a1230b8
name a workspace symbol's module and classes as its containerName, ma…
KotlinIsland Oct 26, 2026
074b19e
give each document symbol a detail, a function's parameters and retur…
KotlinIsland Oct 26, 2026
f0a3b5b
answer by/expressionTypes, every expression of the statement a select…
KotlinIsland Oct 26, 2026
4e623ff
complete a def's name in a class body with what the class can overrid…
KotlinIsland Oct 27, 2026
6253b8f
read an upper-case auto() member of an Enum subclass in a .by file, w…
KotlinIsland Oct 26, 2026
2ee4e7d
name buff as buff in what its server shows, its code actions' titles,…
KotlinIsland Oct 26, 2026
5abe9f8
offer to ignore a diagnostic's rule in the whole file, with a ty: ign…
KotlinIsland Oct 26, 2026
79fed19
register buff's formatting and range formatting for basedpython docum…
KotlinIsland Oct 26, 2026
5373e1c
mark the name of a def or class nested in a function functionScope wh…
KotlinIsland Oct 26, 2026
b4975ef
answer buff/formatSettings, the line length, indentation, quote style…
KotlinIsland Oct 26, 2026
5e4cc4a
extract a run of operands an associative operator chains, b + c in a …
KotlinIsland Oct 26, 2026
f078b89
inline a variable whose value is python's own arithmetic or concatena…
KotlinIsland Oct 26, 2026
222fb31
introduce a parameter, refactor.extract.parameter, whose default is a…
KotlinIsland Oct 26, 2026
584f5da
read completions.importStyle, from or module, for how an auto-import …
KotlinIsland Oct 26, 2026
85b2c4a
answer by/docstringStub, the docstring an editor writes into an empty…
KotlinIsland Oct 26, 2026
393bcb7
say on each def a class body makes in by/syntaxOutline whether it is …
KotlinIsland Oct 26, 2026
f33ebe3
name in by/syntaxOutline the expression of a simple statement or a cl…
KotlinIsland Oct 26, 2026
3993460
check a program by run runs against the python --python or PYTHON nam…
KotlinIsland Oct 26, 2026
cd97c7c
report a string handed to python's re functions as their pattern as P…
KotlinIsland Oct 26, 2026
1afae1f
place an import a completion, quick fix, paste or inlay hint adds whe…
KotlinIsland Oct 26, 2026
f537007
move a module's top-level function, class or variable to another modu…
KotlinIsland Oct 26, 2026
1e54a6f
pull a class's members up into a superclass of the project with by/pu…
KotlinIsland Oct 26, 2026
d2917ad
change a function's parameters with by/changeSignature, after by/prep…
KotlinIsland Oct 26, 2026
7d3fc1a
extract a superclass with by/extractSuperclass, a new class above the…
KotlinIsland Oct 26, 2026
7bd7662
offer inverting an if with an else, De Morgan's law, converting a str…
KotlinIsland Oct 26, 2026
7d2bd0f
name in by/documentUsageCounts, with implementations, each subclass o…
KotlinIsland Oct 26, 2026
9d2cbc4
count a dunder method in by/documentUsageCounts for the methods overr…
KotlinIsland Oct 26, 2026
850d5bf
answer by/references, textDocument/references with what each referenc…
KotlinIsland Oct 26, 2026
a2b17f2
answer by/documentInheritedMembers, the members each class of a docum…
KotlinIsland Oct 26, 2026
840c45a
type in by/expressionTypes the tuple of targets a value is unpacked i…
KotlinIsland Oct 26, 2026
a9b4edc
answer every completion with the textEdit it replaces, what is typed …
KotlinIsland Oct 26, 2026
98e8f8c
answer by/mro, the classes a class inherits from in its method resolu…
KotlinIsland Oct 26, 2026
dfceb6d
label each postfix completion by its name, for, rather than by the sn…
KotlinIsland Oct 26, 2026
8971555
answer by/rules, every rule the type checker reports under by the nam…
KotlinIsland Oct 26, 2026
8a12185
leave a constructor and the methods it calls out of by/documentUsageC…
KotlinIsland Oct 26, 2026
2e80291
answer by/smartCompletion, the completions that fit the type the posi…
KotlinIsland Oct 26, 2026
e473535
give a completion labelled with more than its name the name as its fi…
KotlinIsland Oct 26, 2026
986bd66
say in a resolved extraction's data where the name it made up is, ren…
KotlinIsland Oct 26, 2026
161c6c4
parenthesise an inlined value as an operator's operand only where pyt…
KotlinIsland Oct 26, 2026
056b9b6
say in by/syntaxOutline what a method's first parameter receives, ins…
KotlinIsland Oct 26, 2026
6aa1962
report a pytest run under by run to an IDE's test runner as TeamCity …
KotlinIsland Oct 26, 2026
2dce7fd
report an invalid regex pattern written where it is passed at the cha…
KotlinIsland Oct 26, 2026
e4b91a1
answer by/endpoints, every HTTP route a project serves for an editor'…
KotlinIsland Oct 26, 2026
b138642
answer by/typeDeclaration, the class a dotted type name names, shapes…
KotlinIsland Oct 26, 2026
ca43b01
answer by/resolveMergeConflicts, resolving a merge's conflict where t…
KotlinIsland Oct 26, 2026
ca3547b
place added imports as buff's isort writes them, reading its configur…
KotlinIsland Oct 28, 2026
4916ebf
dedent a raw triple-quoted string to the plain string holding its ded…
KotlinIsland Oct 26, 2026
3e23cab
read a .by file's lone triple-quoted string as the value its dedent l…
KotlinIsland Oct 26, 2026
90738ea
report a bad escape in a regex pattern, \q, [\A], an incomplete \x4, …
KotlinIsland Oct 26, 2026
90ddc43
answer by/prepareMoveSymbol and by/moveSymbol anywhere in a top-level…
KotlinIsland Oct 26, 2026
8f9a4db
register for workspace/didCreateFiles on every module and folder and …
KotlinIsland Oct 26, 2026
36078c4
test that by/extractSuperclass refuses a name that is not an identifi…
KotlinIsland Oct 26, 2026
494b727
rename a function with by/changeSignature's name, wherever the projec…
KotlinIsland Oct 26, 2026
a33e0bd
answer each member by/prepareMoveMembers lists with its detail, a met…
KotlinIsland Oct 26, 2026
097e7fe
pull a base the class statement names up into the superclass's bases …
KotlinIsland Oct 26, 2026
2b89e80
say which document requests answer a closed document's textHash from …
KotlinIsland Oct 26, 2026
314cc49
profile a program with by run --profile PATH, which writes the pstats…
KotlinIsland Oct 26, 2026
ce74558
design by repl, a basedpython session checked and transpiled as one m…
KotlinIsland Oct 26, 2026
ff2f65e
answer by/inputStatus with whether the text typed into a by repl cons…
KotlinIsland Oct 26, 2026
ff4b6e7
transpile a by repl session with Config::session, under which a top-l…
KotlinIsland Oct 26, 2026
2d03dc9
start an interactive basedpython session with by repl, in which each …
KotlinIsland Oct 26, 2026
e09ef2b
check that a console completes against a document holding a by repl s…
KotlinIsland Oct 26, 2026
dd64819
check a by repl session's module as the project's own first-party cod…
KotlinIsland Oct 26, 2026
42d22ef
resolve the call that ends an optional chain against the chain's pres…
KotlinIsland Oct 26, 2026
ebb77fd
insert a sealed class's __sealed_members__ assignment as a statement-…
KotlinIsland Oct 26, 2026
5795762
make the by init test name the interpreter by run runs the new projec…
KotlinIsland Oct 26, 2026
a3f76a4
run the stand-in uv once from the test before the server runs it in t…
KotlinIsland Oct 26, 2026
de509b8
report a \N{...} name in a regex that re would refuse on the python c…
KotlinIsland Oct 26, 2026
cdf1c99
give a sealed class declared in a function or class body its __sealed…
KotlinIsland Oct 27, 2026
4753b23
send a workspace diagnostic request again from the ty_server test cli…
KotlinIsland Oct 27, 2026
7df3f1b
highlight a final written in an annotation, x: final float, where it …
KotlinIsland Oct 27, 2026
f317823
pull bases up into a superclass whose body is only pass without touch…
KotlinIsland Oct 27, 2026
80f6ffc
leave out without includeDeclaration only what declares the name in t…
KotlinIsland Oct 27, 2026
21e305f
indent a postfix statement's new line one level past the line it is w…
KotlinIsland Oct 27, 2026
dc38739
mark each by/injections fragment checked that invalid-regex compiles …
KotlinIsland Oct 27, 2026
e2f0713
answer by/typeDeclaration for a class whose module's source only impo…
KotlinIsland Oct 27, 2026
afd1c7d
switch the postfix templates off with completions.postfixTemplates, o…
KotlinIsland Oct 27, 2026
bf43e02
parse a document as basedpython by its path's extension whatever the …
KotlinIsland Oct 27, 2026
cedb429
tell an editor's console with by repl --events PORT, on a loopback co…
KotlinIsland Oct 27, 2026
f7f96a3
name the runtime's helpers in a by run --profile snapshot <by runtime…
KotlinIsland Oct 27, 2026
1f562d9
start a by repl session in a module of the project with --module, as …
KotlinIsland Oct 27, 2026
26e4335
let an exception a by run program does not catch leave the interprete…
KotlinIsland Oct 27, 2026
38f6d61
keep by's own python out of a by run --profile snapshot and a by repl…
KotlinIsland Oct 27, 2026
f4f93b3
answer initialize with the flags of by repl and by run an editor star…
KotlinIsland Oct 27, 2026
ba2deec
compile a test module and a conftest that pytest's assertion rewriter…
KotlinIsland Oct 27, 2026
3e0c64e
charge each line of the __main__ guard the transpiler appends to the …
KotlinIsland Oct 27, 2026
c8da059
read what a function's body asks of its own signature — an unannotate…
KotlinIsland Oct 27, 2026
fdbbc67
leave an import of a declaration out of its usage count, as one that …
KotlinIsland Oct 27, 2026
2b519ef
update crates/basedpython's own lock file for the dependencies by_sta…
KotlinIsland Oct 27, 2026
d4d2872
write an unannotated parameter's inferred type parameter by the param…
KotlinIsland Oct 27, 2026
49f9c7f
exit by run with 128 plus the signal's number when a signal ends the …
KotlinIsland Oct 27, 2026
a1bf977
find by run --coverage's project directory without os.path.relpath, w…
KotlinIsland Oct 27, 2026
328ed29
install pinned pytest and coverage.py into ci's test interpreter, so …
KotlinIsland Oct 27, 2026
c8e904a
say in the cli reference that a by run --coverage run ended by os.exe…
KotlinIsland Oct 28, 2026
e84c6f2
correct what dedent-strings.md says a dedented string is: no bytes or…
KotlinIsland Oct 28, 2026
230c8be
drop hawk.toml's expectation for TargetVersion::linter_version, which…
KotlinIsland Oct 28, 2026
ecde896
test by run --coverage's report of a module that never ran on each co…
KotlinIsland Oct 29, 2026
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
11 changes: 11 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,17 @@ jobs:
# interpreters as externally managed, though this one belongs to the job alone
- name: "Install `typing_extensions` into the interpreter"
run: uv pip install --python "$PYTHON" --break-system-packages "typing_extensions==4.16.0"
# the end-to-end tests of `by run --coverage` and of a pytest run need coverage.py and
# pytest, and skip on an interpreter without them, as a contributor's may be. this one is
# given both, as the `test-python` dependency group locks them, and says so: while
# `BY_TEST_PYTHON_PROVIDES` names a module, a test that cannot import it fails rather
# than skips
- name: "Install pytest and coverage.py into the interpreter"
run: |
uv export --only-group test-python --no-emit-project --output-file "$RUNNER_TEMP/test-python.txt"
uv pip install --python "$PYTHON" --break-system-packages --require-hashes \
--requirements "$RUNNER_TEMP/test-python.txt"
echo "BY_TEST_PYTHON_PROVIDES=pytest coverage" >> "$GITHUB_ENV"
# a separate invocation on purpose: the backend's differential tests fork processes
# and compile C, and sharing a run with `by_transforms`' ~1800 other tests starves
# them into failures that pass on their own
Expand Down
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ PYTHON=$(which python3.13) CARGO_PROFILE_DEV_OPT_LEVEL=1 CARGO_PROFILE_DEV_LTO=o

CI pins it in a dedicated step, so it never sees this.

The end-to-end tests of a `pytest` or `--coverage` run skip when `$PYTHON` cannot import `pytest` or
`coverage`. Setting `BY_TEST_PYTHON_PROVIDES="pytest coverage"`, the modules the interpreter was
given, makes them fail instead when it cannot import one. CI sets it.

### Fallback without nextest

If `cargo nextest` is not available, use `cargo test` with the same environment variables. For the workspace, exclude `ty` and then run its other test targets explicitly. If new non-watcher test targets are added to `ty`, add them to the `ty` command below; `cargo metadata --no-deps --format-version 1` lists each crate's targets:
Expand Down
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions crates/basedpython/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions crates/by_stage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ doctest = false
[dependencies]
by_transforms = { workspace = true }
ruff_db = { workspace = true, features = ["os"] }
ruff_python_ast = { workspace = true }
ruff_python_parser = { workspace = true }
ruff_text_size = { workspace = true }
ty_module_resolver = { workspace = true }
ty_project = { workspace = true }
ty_python_semantic = { workspace = true }
Expand Down
3 changes: 3 additions & 0 deletions crates/by_stage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
//! which source, for an editor to ask.
//! - [`run_module`] — which file `by run <module>` executes, and the module a
//! file runs as.
//! - [`session`] — a `by repl` session, and whether what has been typed into it
//! is a whole input yet

pub mod emit;
pub mod layout;
Expand All @@ -57,6 +59,7 @@ pub mod record;
pub mod restage;
pub mod run_module;
pub mod runtime;
pub mod session;
pub mod sourcemap;
pub mod staging;
pub mod verbatim;
71 changes: 69 additions & 2 deletions crates/by_stage/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use std::path::{Path, PathBuf};

use anyhow::Context;
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
use ty_project::metadata::options::{EnvironmentOptions, Options};
use ty_project::metadata::value::RelativePathBuf;
use ty_project::{Db, ProjectDatabase, ProjectMetadata};

/// Everything needed to build a project db a second time.
Expand Down Expand Up @@ -96,11 +98,50 @@ impl Rebuilder {
}

pub fn rebuild(&self) -> Box<dyn ty_python_semantic::Db> {
Box::new(self.project_database())
}

/// the same project with `extra` one of its first-party roots too, searched after its own
///
/// a `by repl` session's module lives outside the project, and the checker reads a module
/// as the project's own code only from a first-party root: a `sealed` class declared in a
/// session can be subclassed in the session, as in any module of the project, only once the
/// session's module is first-party
#[must_use]
pub fn with_first_party_root(&self, extra: &SystemPath) -> Self {
let db = self.project_database();
let mut roots: Vec<RelativePathBuf> = db
.project()
.program(&db)
.search_paths(&db)
.first_party_roots()
.map(RelativePathBuf::cli)
.collect();
roots.push(RelativePathBuf::cli(extra));
let mut metadata = self.metadata.clone();
metadata.apply_override_options(Options {
environment: Some(EnvironmentOptions {
root: Some(roots),
..EnvironmentOptions::default()
}),
..Options::default()
});
Self {
metadata,
root: self.root.clone(),
included: self.included.clone(),
}
}

/// the project's db built again, and not frozen: what a caller holds that goes on
/// changing an input after the build, as a `by repl` session changes its module with
/// every input
pub fn project_database(&self) -> ProjectDatabase {
let mut db =
ProjectDatabase::use_defaults(self.metadata.clone(), OsSystem::new(&self.root));
db.project()
.set_included_paths(&mut db, self.included.clone());
Box::new(db)
db
}
}

Expand Down Expand Up @@ -267,6 +308,23 @@ pub fn build_project_db(
cwd: &Path,
extensions: &[&str],
output: Option<&Path>,
) -> anyhow::Result<ProjectBuild> {
build_project_db_for(cwd, extensions, output, None)
}

/// [`build_project_db`], checking the project against the python environment `python` — an
/// interpreter or the environment holding it, as `by check --python` takes — rather than the
/// one the project's configuration and discovery would find
///
/// what runs a program decides which packages it imports, so a command that runs the program on
/// an interpreter it was told about has to check it against that interpreter's packages: checked
/// against another environment, an import the program will find is reported as unresolved, and
/// one it will not find passes
pub fn build_project_db_for(
cwd: &Path,
extensions: &[&str],
output: Option<&Path>,
python: Option<&SystemPath>,
) -> anyhow::Result<ProjectBuild> {
// the project root must be canonicalized the same way the included files
// are (below) so it stays a path *prefix* of them: otherwise a file's
Expand All @@ -278,8 +336,17 @@ pub fn build_project_db(
let sys_cwd = SystemPath::from_std_path(&canonical_cwd)
.with_context(|| format!("non-utf8 path: {}", canonical_cwd.display()))?;
let system = OsSystem::new(sys_cwd);
let project_metadata = ProjectMetadata::discover(sys_cwd, &system)
let mut project_metadata = ProjectMetadata::discover(sys_cwd, &system)
.with_context(|| format!("failed to discover project at {sys_cwd}"))?;
if let Some(python) = python {
project_metadata.set_override_options(Options {
environment: Some(EnvironmentOptions {
python: Some(RelativePathBuf::cli(python)),
..EnvironmentOptions::default()
}),
..Options::default()
});
}

// the project is the project wherever the command was run from. rooting this
// at the working directory instead means `by run` inside `tests/` transpiles
Expand Down
Loading
Loading