mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 06:11:21 +00:00

Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
This PR ensures that we always put `./src` before `.` in our list of first-party search paths. This better emulates the fact that at runtime, the module name of a file `src/foo.py` would almost certainly be `foo` rather than `src.foo`. I wondered if fixing this might fix https://github.com/astral-sh/ruff/pull/20603#issuecomment-3345317444. It seems like that's not the case, but it also seems like it leads to better diagnostics because we report much more intuitive module names to the user in our error messages -- so, it's probably a good change anyway.
2039 lines
62 KiB
Rust
2039 lines
62 KiB
Rust
use insta_cmd::assert_cmd_snapshot;
|
|
use ruff_python_ast::PythonVersion;
|
|
|
|
use crate::CliTest;
|
|
|
|
/// Specifying an option on the CLI should take precedence over the same setting in the
|
|
/// project's configuration. Here, this is tested for the Python version.
|
|
#[test]
|
|
fn config_override_python_version() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.environment]
|
|
python-version = "3.11"
|
|
"#,
|
|
),
|
|
(
|
|
"test.py",
|
|
r#"
|
|
import sys
|
|
|
|
# Access `sys.last_exc` that was only added in Python 3.12
|
|
print(sys.last_exc)
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-attribute]: Type `<module 'sys'>` has no attribute `last_exc`
|
|
--> test.py:5:7
|
|
|
|
|
4 | # Access `sys.last_exc` that was only added in Python 3.12
|
|
5 | print(sys.last_exc)
|
|
| ^^^^^^^^^^^^
|
|
|
|
|
info: rule `unresolved-attribute` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
assert_cmd_snapshot!(case.command().arg("--python-version").arg("3.12"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Same as above, but for the Python platform.
|
|
#[test]
|
|
fn config_override_python_platform() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.environment]
|
|
python-platform = "linux"
|
|
"#,
|
|
),
|
|
(
|
|
"test.py",
|
|
r#"
|
|
import sys
|
|
from typing_extensions import reveal_type
|
|
|
|
reveal_type(sys.platform)
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
info[revealed-type]: Revealed type
|
|
--> test.py:5:13
|
|
|
|
|
3 | from typing_extensions import reveal_type
|
|
4 |
|
|
5 | reveal_type(sys.platform)
|
|
| ^^^^^^^^^^^^ `Literal["linux"]`
|
|
|
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
assert_cmd_snapshot!(case.command().arg("--python-platform").arg("all"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
info[revealed-type]: Revealed type
|
|
--> test.py:5:13
|
|
|
|
|
3 | from typing_extensions import reveal_type
|
|
4 |
|
|
5 | reveal_type(sys.platform)
|
|
| ^^^^^^^^^^^^ `LiteralString`
|
|
|
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn config_file_annotation_showing_where_python_version_set_typing_error() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.environment]
|
|
python-version = "3.8"
|
|
"#,
|
|
),
|
|
(
|
|
"test.py",
|
|
r#"
|
|
aiter
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-reference]: Name `aiter` used when not defined
|
|
--> test.py:2:1
|
|
|
|
|
2 | aiter
|
|
| ^^^^^
|
|
|
|
|
info: `aiter` was added as a builtin in Python 3.10
|
|
info: Python 3.8 was assumed when resolving types
|
|
--> pyproject.toml:3:18
|
|
|
|
|
2 | [tool.ty.environment]
|
|
3 | python-version = "3.8"
|
|
| ^^^^^ Python 3.8 assumed due to this configuration setting
|
|
|
|
|
info: rule `unresolved-reference` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
assert_cmd_snapshot!(case.command().arg("--python-version=3.9"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-reference]: Name `aiter` used when not defined
|
|
--> test.py:2:1
|
|
|
|
|
2 | aiter
|
|
| ^^^^^
|
|
|
|
|
info: `aiter` was added as a builtin in Python 3.10
|
|
info: Python 3.9 was assumed when resolving types because it was specified on the command line
|
|
info: rule `unresolved-reference` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// If `.` and `./src` are both registered as first-party search paths,
|
|
/// the `./src` directory should take precedence for module resolution,
|
|
/// because it is relative to `.`.
|
|
#[test]
|
|
fn src_subdirectory_takes_precedence_over_repo_root() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([(
|
|
"src/package/__init__.py",
|
|
"from . import nonexistent_submodule",
|
|
)])?;
|
|
|
|
// If `./src` didn't take priority over `.` here, we would report
|
|
// "Module `src.package` has no member `nonexistent_submodule`"
|
|
// instead of "Module `package` has no member `nonexistent_submodule`".
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package` has no member `nonexistent_submodule`
|
|
--> src/package/__init__.py:1:15
|
|
|
|
|
1 | from . import nonexistent_submodule
|
|
| ^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// This tests that, even if no Python *version* has been specified on the CLI or in a config file,
|
|
/// ty is still able to infer the Python version from a `--python` argument on the CLI,
|
|
/// *even if* the `--python` argument points to a system installation.
|
|
///
|
|
/// We currently cannot infer the Python version from a system installation on Windows:
|
|
/// on Windows, we can only infer the Python version from a virtual environment.
|
|
/// This is because we use the layout of the Python installation to infer the Python version:
|
|
/// on Unix, the `site-packages` directory of an installation will be located at
|
|
/// `<sys.prefix>/lib/pythonX.Y/site-packages`. On Windows, however, the `site-packages`
|
|
/// directory will be located at `<sys.prefix>/Lib/site-packages`, which doesn't give us the
|
|
/// same information.
|
|
#[cfg(not(windows))]
|
|
#[test]
|
|
fn python_version_inferred_from_system_installation() -> anyhow::Result<()> {
|
|
let cpython_case = CliTest::with_files([
|
|
("pythons/Python3.8/bin/python", ""),
|
|
("pythons/Python3.8/lib/python3.8/site-packages/foo.py", ""),
|
|
("test.py", "aiter"),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(cpython_case.command().arg("--python").arg("pythons/Python3.8/bin/python"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-reference]: Name `aiter` used when not defined
|
|
--> test.py:1:1
|
|
|
|
|
1 | aiter
|
|
| ^^^^^
|
|
|
|
|
info: `aiter` was added as a builtin in Python 3.10
|
|
info: Python 3.8 was assumed when resolving types because of the layout of your Python installation
|
|
info: The primary `site-packages` directory of your installation was found at `lib/python3.8/site-packages/`
|
|
info: No Python version was specified on the command line or in a configuration file
|
|
info: rule `unresolved-reference` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
let pypy_case = CliTest::with_files([
|
|
("pythons/pypy3.8/bin/python", ""),
|
|
("pythons/pypy3.8/lib/pypy3.8/site-packages/foo.py", ""),
|
|
("test.py", "aiter"),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(pypy_case.command().arg("--python").arg("pythons/pypy3.8/bin/python"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-reference]: Name `aiter` used when not defined
|
|
--> test.py:1:1
|
|
|
|
|
1 | aiter
|
|
| ^^^^^
|
|
|
|
|
info: `aiter` was added as a builtin in Python 3.10
|
|
info: Python 3.8 was assumed when resolving types because of the layout of your Python installation
|
|
info: The primary `site-packages` directory of your installation was found at `lib/pypy3.8/site-packages/`
|
|
info: No Python version was specified on the command line or in a configuration file
|
|
info: rule `unresolved-reference` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
let free_threaded_case = CliTest::with_files([
|
|
("pythons/Python3.13t/bin/python", ""),
|
|
(
|
|
"pythons/Python3.13t/lib/python3.13t/site-packages/foo.py",
|
|
"",
|
|
),
|
|
("test.py", "import string.templatelib"),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(free_threaded_case.command().arg("--python").arg("pythons/Python3.13t/bin/python"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `string.templatelib`
|
|
--> test.py:1:8
|
|
|
|
|
1 | import string.templatelib
|
|
| ^^^^^^^^^^^^^^^^^^
|
|
|
|
|
info: The stdlib module `string.templatelib` is only available on Python 3.14+
|
|
info: Python 3.13 was assumed when resolving modules because of the layout of your Python installation
|
|
info: The primary `site-packages` directory of your installation was found at `lib/python3.13t/site-packages/`
|
|
info: No Python version was specified on the command line or in a configuration file
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// On Unix systems, it's common for a Python installation at `.venv/bin/python` to only be a symlink
|
|
/// to a system Python installation. We must be careful not to resolve the symlink too soon!
|
|
/// If we do, we will incorrectly add the system installation's `site-packages` as a search path,
|
|
/// when we should be adding the virtual environment's `site-packages` directory as a search path instead.
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn python_argument_points_to_symlinked_executable() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"system-installation/lib/python3.13/site-packages/foo.py",
|
|
"",
|
|
),
|
|
("system-installation/bin/python", ""),
|
|
(
|
|
"strange-venv-location/lib/python3.13/site-packages/bar.py",
|
|
"",
|
|
),
|
|
(
|
|
"test.py",
|
|
"\
|
|
import foo
|
|
import bar",
|
|
),
|
|
])?;
|
|
|
|
case.write_symlink(
|
|
"system-installation/bin/python",
|
|
"strange-venv-location/bin/python",
|
|
)?;
|
|
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg("strange-venv-location/bin/python"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `foo`
|
|
--> test.py:1:8
|
|
|
|
|
1 | import foo
|
|
| ^^^
|
|
2 | import bar
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/ (first-party code)
|
|
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: 3. <temp_dir>/strange-venv-location/lib/python3.13/site-packages (site-packages)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// On Unix systems, a virtual environment can come with multiple `site-packages` directories:
|
|
/// one at `<sys.prefix>/lib/pythonX.Y/site-packages` and one at
|
|
/// `<sys.prefix>/lib64/pythonX.Y/site-packages`. According to [the stdlib docs], the `lib64`
|
|
/// is not *meant* to have any Python files in it (only C extensions and similar). Empirically,
|
|
/// however, it sometimes does indeed have Python files in it: popular tools such as poetry
|
|
/// appear to sometimes install Python packages into the `lib64` site-packages directory even
|
|
/// though they probably shouldn't. We therefore check for both a `lib64` and a `lib` directory,
|
|
/// and add them both as search paths if they both exist.
|
|
///
|
|
/// See:
|
|
/// - <https://github.com/astral-sh/ty/issues/1043>
|
|
/// - <https://github.com/astral-sh/ty/issues/257>.
|
|
///
|
|
/// [the stdlib docs]: https://docs.python.org/3/library/sys.html#sys.platlibdir
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn lib64_site_packages_directory_on_unix() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(".venv/lib/python3.13/site-packages/foo.py", ""),
|
|
(".venv/lib64/python3.13/site-packages/bar.py", ""),
|
|
("test.py", "import foo, bar, baz"),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg(".venv"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `baz`
|
|
--> test.py:1:18
|
|
|
|
|
1 | import foo, bar, baz
|
|
| ^^^
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/ (first-party code)
|
|
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: 3. <temp_dir>/.venv/lib/python3.13/site-packages (site-packages)
|
|
info: 4. <temp_dir>/.venv/lib64/python3.13/site-packages (site-packages)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn pyvenv_cfg_file_annotation_showing_where_python_version_set() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.environment]
|
|
python = "venv"
|
|
"#,
|
|
),
|
|
(
|
|
"venv/pyvenv.cfg",
|
|
r#"
|
|
version = 3.8
|
|
home = foo/bar/bin
|
|
"#,
|
|
),
|
|
if cfg!(target_os = "windows") {
|
|
("foo/bar/bin/python.exe", "")
|
|
} else {
|
|
("foo/bar/bin/python", "")
|
|
},
|
|
if cfg!(target_os = "windows") {
|
|
("venv/Lib/site-packages/foo.py", "")
|
|
} else {
|
|
("venv/lib/python3.8/site-packages/foo.py", "")
|
|
},
|
|
("test.py", "aiter"),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-reference]: Name `aiter` used when not defined
|
|
--> test.py:1:1
|
|
|
|
|
1 | aiter
|
|
| ^^^^^
|
|
|
|
|
info: `aiter` was added as a builtin in Python 3.10
|
|
info: Python 3.8 was assumed when resolving types because of your virtual environment
|
|
--> venv/pyvenv.cfg:2:11
|
|
|
|
|
2 | version = 3.8
|
|
| ^^^ Python version inferred from virtual environment metadata file
|
|
3 | home = foo/bar/bin
|
|
|
|
|
info: No Python version was specified on the command line or in a configuration file
|
|
info: rule `unresolved-reference` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn pyvenv_cfg_file_annotation_no_trailing_newline() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.environment]
|
|
python = "venv"
|
|
"#,
|
|
),
|
|
(
|
|
"venv/pyvenv.cfg",
|
|
r#"home = foo/bar/bin
|
|
|
|
|
|
version = 3.8"#,
|
|
),
|
|
if cfg!(target_os = "windows") {
|
|
("foo/bar/bin/python.exe", "")
|
|
} else {
|
|
("foo/bar/bin/python", "")
|
|
},
|
|
if cfg!(target_os = "windows") {
|
|
("venv/Lib/site-packages/foo.py", "")
|
|
} else {
|
|
("venv/lib/python3.8/site-packages/foo.py", "")
|
|
},
|
|
("test.py", "aiter"),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-reference]: Name `aiter` used when not defined
|
|
--> test.py:1:1
|
|
|
|
|
1 | aiter
|
|
| ^^^^^
|
|
|
|
|
info: `aiter` was added as a builtin in Python 3.10
|
|
info: Python 3.8 was assumed when resolving types because of your virtual environment
|
|
--> venv/pyvenv.cfg:4:23
|
|
|
|
|
4 | version = 3.8
|
|
| ^^^ Python version inferred from virtual environment metadata file
|
|
|
|
|
info: No Python version was specified on the command line or in a configuration file
|
|
info: rule `unresolved-reference` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn config_file_annotation_showing_where_python_version_set_syntax_error() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[project]
|
|
requires-python = ">=3.8"
|
|
"#,
|
|
),
|
|
(
|
|
"test.py",
|
|
r#"
|
|
match object():
|
|
case int():
|
|
pass
|
|
case _:
|
|
pass
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[invalid-syntax]
|
|
--> test.py:2:1
|
|
|
|
|
2 | match object():
|
|
| ^^^^^ Cannot use `match` statement on Python 3.8 (syntax was added in Python 3.10)
|
|
3 | case int():
|
|
4 | pass
|
|
|
|
|
info: Python 3.8 was assumed when parsing syntax
|
|
--> pyproject.toml:3:19
|
|
|
|
|
2 | [project]
|
|
3 | requires-python = ">=3.8"
|
|
| ^^^^^^^ Python 3.8 assumed due to this configuration setting
|
|
|
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
assert_cmd_snapshot!(case.command().arg("--python-version=3.9"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[invalid-syntax]
|
|
--> test.py:2:1
|
|
|
|
|
2 | match object():
|
|
| ^^^^^ Cannot use `match` statement on Python 3.9 (syntax was added in Python 3.10)
|
|
3 | case int():
|
|
4 | pass
|
|
|
|
|
info: Python 3.9 was assumed when parsing syntax because it was specified on the command line
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn python_cli_argument_virtual_environment() -> anyhow::Result<()> {
|
|
let path_to_executable = if cfg!(windows) {
|
|
"my-venv/Scripts/python.exe"
|
|
} else {
|
|
"my-venv/bin/python"
|
|
};
|
|
|
|
let other_venv_path = "my-venv/foo/some_other_file.txt";
|
|
|
|
let case = CliTest::with_files([
|
|
("test.py", ""),
|
|
(
|
|
if cfg!(windows) {
|
|
"my-venv/Lib/site-packages/foo.py"
|
|
} else {
|
|
"my-venv/lib/python3.13/site-packages/foo.py"
|
|
},
|
|
"",
|
|
),
|
|
(path_to_executable, ""),
|
|
(other_venv_path, ""),
|
|
])?;
|
|
|
|
// Passing a path to the installation works
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg("my-venv"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// And so does passing a path to the executable inside the installation
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg(path_to_executable), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// But random other paths inside the installation are rejected
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg(other_venv_path), @r"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
ty failed
|
|
Cause: Invalid `--python` argument `<temp_dir>/my-venv/foo/some_other_file.txt`: does not point to a Python executable or a directory on disk
|
|
");
|
|
|
|
// And so are paths that do not exist on disk
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg("not-a-directory-or-executable"), @r"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
ty failed
|
|
Cause: Invalid `--python` argument `<temp_dir>/not-a-directory-or-executable`: does not point to a Python executable or a directory on disk
|
|
Cause: No such file or directory (os error 2)
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn python_cli_argument_system_installation() -> anyhow::Result<()> {
|
|
let path_to_executable = if cfg!(windows) {
|
|
"Python3.11/python.exe"
|
|
} else {
|
|
"Python3.11/bin/python"
|
|
};
|
|
|
|
let case = CliTest::with_files([
|
|
("test.py", ""),
|
|
(
|
|
if cfg!(windows) {
|
|
"Python3.11/Lib/site-packages/foo.py"
|
|
} else {
|
|
"Python3.11/lib/python3.11/site-packages/foo.py"
|
|
},
|
|
"",
|
|
),
|
|
(path_to_executable, ""),
|
|
])?;
|
|
|
|
// Passing a path to the installation works
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg("Python3.11"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// And so does passing a path to the executable inside the installation
|
|
assert_cmd_snapshot!(case.command().arg("--python").arg(path_to_executable), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn config_file_broken_python_setting() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[project]
|
|
name = "test"
|
|
version = "0.1.0"
|
|
description = "Some description"
|
|
readme = "README.md"
|
|
requires-python = ">=3.13"
|
|
dependencies = []
|
|
|
|
[tool.ty.environment]
|
|
python = "not-a-directory-or-executable"
|
|
"#,
|
|
),
|
|
("test.py", ""),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
ty failed
|
|
Cause: Invalid `environment.python` setting
|
|
|
|
--> Invalid setting in configuration file `<temp_dir>/pyproject.toml`
|
|
|
|
|
9 |
|
|
10 | [tool.ty.environment]
|
|
11 | python = "not-a-directory-or-executable"
|
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not point to a Python executable or a directory on disk
|
|
|
|
|
|
|
Cause: No such file or directory (os error 2)
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn config_file_python_setting_directory_with_no_site_packages() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.environment]
|
|
python = "directory-but-no-site-packages"
|
|
"#,
|
|
),
|
|
("directory-but-no-site-packages/lib/foo.py", ""),
|
|
("test.py", ""),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
ty failed
|
|
Cause: Failed to discover the site-packages directory
|
|
Cause: Invalid `environment.python` setting
|
|
|
|
--> Invalid setting in configuration file `<temp_dir>/pyproject.toml`
|
|
|
|
|
1 |
|
|
2 | [tool.ty.environment]
|
|
3 | python = "directory-but-no-site-packages"
|
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not find a `site-packages` directory for this Python installation/executable
|
|
|
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// This error message is never emitted on Windows, because Windows installations have simpler layouts
|
|
#[cfg(not(windows))]
|
|
#[test]
|
|
fn unix_system_installation_with_no_lib_directory() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.environment]
|
|
python = "directory-but-no-site-packages"
|
|
"#,
|
|
),
|
|
("directory-but-no-site-packages/foo.py", ""),
|
|
("test.py", ""),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
ty failed
|
|
Cause: Failed to discover the site-packages directory
|
|
Cause: Failed to iterate over the contents of the `lib`/`lib64` directories of the Python installation
|
|
|
|
--> Invalid setting in configuration file `<temp_dir>/pyproject.toml`
|
|
|
|
|
1 |
|
|
2 | [tool.ty.environment]
|
|
3 | python = "directory-but-no-site-packages"
|
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn defaults_to_a_new_python_version() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"ty.toml",
|
|
&*format!(
|
|
r#"
|
|
[environment]
|
|
python-version = "{}"
|
|
python-platform = "linux"
|
|
"#,
|
|
PythonVersion::default()
|
|
),
|
|
),
|
|
(
|
|
"main.py",
|
|
r#"
|
|
import os
|
|
|
|
os.grantpt(1) # only available on unix, Python 3.13 or newer
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-attribute]: Type `<module 'os'>` has no attribute `grantpt`
|
|
--> main.py:4:1
|
|
|
|
|
2 | import os
|
|
3 |
|
|
4 | os.grantpt(1) # only available on unix, Python 3.13 or newer
|
|
| ^^^^^^^^^^
|
|
|
|
|
info: rule `unresolved-attribute` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// Use default (which should be latest supported)
|
|
let case = CliTest::with_files([
|
|
(
|
|
"ty.toml",
|
|
r#"
|
|
[environment]
|
|
python-platform = "linux"
|
|
"#,
|
|
),
|
|
(
|
|
"main.py",
|
|
r#"
|
|
import os
|
|
|
|
os.grantpt(1) # only available on unix, Python 3.13 or newer
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// The `site-packages` directory is used by ty for external import.
|
|
/// Ty does the following checks to discover the `site-packages` directory in the order:
|
|
/// 1) If `VIRTUAL_ENV` environment variable is set
|
|
/// 2) If `CONDA_PREFIX` environment variable is set (and .filename != `CONDA_DEFAULT_ENV`)
|
|
/// 3) If a `.venv` directory exists at the project root
|
|
/// 4) If `CONDA_PREFIX` environment variable is set (and .filename == `CONDA_DEFAULT_ENV`)
|
|
///
|
|
/// This test (and the next one) is aiming at validating the logic around these cases.
|
|
///
|
|
/// To do this we create a program that has these 4 imports:
|
|
///
|
|
/// ```python
|
|
/// from package1 import ActiveVenv
|
|
/// from package1 import ChildConda
|
|
/// from package1 import WorkingVenv
|
|
/// from package1 import BaseConda
|
|
/// ```
|
|
///
|
|
/// We then create 4 different copies of package1. Each copy defines all of these
|
|
/// classes... except the one that describes it. Therefore we know we got e.g.
|
|
/// the working venv if we get a diagnostic like this:
|
|
///
|
|
/// ```text
|
|
/// Unresolved import
|
|
/// 4 | from package1 import WorkingVenv
|
|
/// | ^^^^^^^^^^^
|
|
/// ```
|
|
///
|
|
/// This test uses a directory structure as follows:
|
|
///
|
|
/// ├── project
|
|
/// │ ├── test.py
|
|
/// │ └── .venv
|
|
/// │ ├── pyvenv.cfg
|
|
/// │ └── lib
|
|
/// │ └── python3.13
|
|
/// │ └── site-packages
|
|
/// │ └── package1
|
|
/// │ └── __init__.py
|
|
/// ├── myvenv
|
|
/// │ ├── pyvenv.cfg
|
|
/// │ └── lib
|
|
/// │ └── python3.13
|
|
/// │ └── site-packages
|
|
/// │ └── package1
|
|
/// │ └── __init__.py
|
|
/// ├── conda-env
|
|
/// │ └── lib
|
|
/// │ └── python3.13
|
|
/// │ └── site-packages
|
|
/// │ └── package1
|
|
/// │ └── __init__.py
|
|
/// └── conda
|
|
/// └── envs
|
|
/// └── base
|
|
/// └── lib
|
|
/// └── python3.13
|
|
/// └── site-packages
|
|
/// └── package1
|
|
/// └── __init__.py
|
|
///
|
|
/// test.py imports package1
|
|
/// And the command is run in the `child` directory.
|
|
#[test]
|
|
fn check_venv_resolution_with_working_venv() -> anyhow::Result<()> {
|
|
let child_conda_package1_path = if cfg!(windows) {
|
|
"conda-env/Lib/site-packages/package1/__init__.py"
|
|
} else {
|
|
"conda-env/lib/python3.13/site-packages/package1/__init__.py"
|
|
};
|
|
|
|
let base_conda_package1_path = if cfg!(windows) {
|
|
"conda/envs/base/Lib/site-packages/package1/__init__.py"
|
|
} else {
|
|
"conda/envs/base/lib/python3.13/site-packages/package1/__init__.py"
|
|
};
|
|
|
|
let working_venv_package1_path = if cfg!(windows) {
|
|
"project/.venv/Lib/site-packages/package1/__init__.py"
|
|
} else {
|
|
"project/.venv/lib/python3.13/site-packages/package1/__init__.py"
|
|
};
|
|
|
|
let active_venv_package1_path = if cfg!(windows) {
|
|
"myvenv/Lib/site-packages/package1/__init__.py"
|
|
} else {
|
|
"myvenv/lib/python3.13/site-packages/package1/__init__.py"
|
|
};
|
|
|
|
let case = CliTest::with_files([
|
|
(
|
|
"project/test.py",
|
|
r#"
|
|
from package1 import ActiveVenv
|
|
from package1 import ChildConda
|
|
from package1 import WorkingVenv
|
|
from package1 import BaseConda
|
|
"#,
|
|
),
|
|
(
|
|
"project/.venv/pyvenv.cfg",
|
|
r#"
|
|
home = ./
|
|
|
|
"#,
|
|
),
|
|
(
|
|
"myvenv/pyvenv.cfg",
|
|
r#"
|
|
home = ./
|
|
|
|
"#,
|
|
),
|
|
(
|
|
active_venv_package1_path,
|
|
r#"
|
|
class ChildConda: ...
|
|
class WorkingVenv: ...
|
|
class BaseConda: ...
|
|
"#,
|
|
),
|
|
(
|
|
child_conda_package1_path,
|
|
r#"
|
|
class ActiveVenv: ...
|
|
class WorkingVenv: ...
|
|
class BaseConda: ...
|
|
"#,
|
|
),
|
|
(
|
|
working_venv_package1_path,
|
|
r#"
|
|
class ActiveVenv: ...
|
|
class ChildConda: ...
|
|
class BaseConda: ...
|
|
"#,
|
|
),
|
|
(
|
|
base_conda_package1_path,
|
|
r#"
|
|
class ActiveVenv: ...
|
|
class ChildConda: ...
|
|
class WorkingVenv: ...
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
// Run with nothing set, should find the working venv
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `WorkingVenv`
|
|
--> test.py:4:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
| ^^^^^^^^^^^
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// Run with VIRTUAL_ENV set, should find the active venv
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("VIRTUAL_ENV", case.root().join("myvenv")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ActiveVenv`
|
|
--> test.py:2:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
| ^^^^^^^^^^
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX set, should find the child conda
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda-env")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ChildConda`
|
|
--> test.py:3:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
| ^^^^^^^^^^
|
|
4 | from package1 import WorkingVenv
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX and CONDA_DEFAULT_ENV set (unequal), should find child conda
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda-env"))
|
|
.env("CONDA_DEFAULT_ENV", "base"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ChildConda`
|
|
--> test.py:3:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
| ^^^^^^^^^^
|
|
4 | from package1 import WorkingVenv
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX and CONDA_DEFAULT_ENV (unequal) and VIRTUAL_ENV set,
|
|
// should find child active venv
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda-env"))
|
|
.env("CONDA_DEFAULT_ENV", "base")
|
|
.env("VIRTUAL_ENV", case.root().join("myvenv")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ActiveVenv`
|
|
--> test.py:2:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
| ^^^^^^^^^^
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX and CONDA_DEFAULT_ENV (equal!) set, should find working venv
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda/envs/base"))
|
|
.env("CONDA_DEFAULT_ENV", "base"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `WorkingVenv`
|
|
--> test.py:4:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
| ^^^^^^^^^^^
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// The exact same test as above, but without a working venv
|
|
///
|
|
/// In this case the Base Conda should be a possible outcome.
|
|
#[test]
|
|
fn check_venv_resolution_without_working_venv() -> anyhow::Result<()> {
|
|
let child_conda_package1_path = if cfg!(windows) {
|
|
"conda-env/Lib/site-packages/package1/__init__.py"
|
|
} else {
|
|
"conda-env/lib/python3.13/site-packages/package1/__init__.py"
|
|
};
|
|
|
|
let base_conda_package1_path = if cfg!(windows) {
|
|
"conda/envs/base/Lib/site-packages/package1/__init__.py"
|
|
} else {
|
|
"conda/envs/base/lib/python3.13/site-packages/package1/__init__.py"
|
|
};
|
|
|
|
let active_venv_package1_path = if cfg!(windows) {
|
|
"myvenv/Lib/site-packages/package1/__init__.py"
|
|
} else {
|
|
"myvenv/lib/python3.13/site-packages/package1/__init__.py"
|
|
};
|
|
|
|
let case = CliTest::with_files([
|
|
(
|
|
"project/test.py",
|
|
r#"
|
|
from package1 import ActiveVenv
|
|
from package1 import ChildConda
|
|
from package1 import WorkingVenv
|
|
from package1 import BaseConda
|
|
"#,
|
|
),
|
|
(
|
|
"myvenv/pyvenv.cfg",
|
|
r#"
|
|
home = ./
|
|
|
|
"#,
|
|
),
|
|
(
|
|
active_venv_package1_path,
|
|
r#"
|
|
class ChildConda: ...
|
|
class WorkingVenv: ...
|
|
class BaseConda: ...
|
|
"#,
|
|
),
|
|
(
|
|
child_conda_package1_path,
|
|
r#"
|
|
class ActiveVenv: ...
|
|
class WorkingVenv: ...
|
|
class BaseConda: ...
|
|
"#,
|
|
),
|
|
(
|
|
base_conda_package1_path,
|
|
r#"
|
|
class ActiveVenv: ...
|
|
class ChildConda: ...
|
|
class WorkingVenv: ...
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
// Run with nothing set, should fail to find anything
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `package1`
|
|
--> test.py:2:6
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
| ^^^^^^^^
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/project (first-party code)
|
|
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
error[unresolved-import]: Cannot resolve imported module `package1`
|
|
--> test.py:3:6
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
| ^^^^^^^^
|
|
4 | from package1 import WorkingVenv
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/project (first-party code)
|
|
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
error[unresolved-import]: Cannot resolve imported module `package1`
|
|
--> test.py:4:6
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
| ^^^^^^^^
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/project (first-party code)
|
|
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
error[unresolved-import]: Cannot resolve imported module `package1`
|
|
--> test.py:5:6
|
|
|
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
5 | from package1 import BaseConda
|
|
| ^^^^^^^^
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/project (first-party code)
|
|
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 4 diagnostics
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// Run with VIRTUAL_ENV set, should find the active venv
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("VIRTUAL_ENV", case.root().join("myvenv")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ActiveVenv`
|
|
--> test.py:2:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
| ^^^^^^^^^^
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX set, should find the child conda
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda-env")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ChildConda`
|
|
--> test.py:3:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
| ^^^^^^^^^^
|
|
4 | from package1 import WorkingVenv
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX and CONDA_DEFAULT_ENV set (unequal), should find child conda
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda-env"))
|
|
.env("CONDA_DEFAULT_ENV", "base"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ChildConda`
|
|
--> test.py:3:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
3 | from package1 import ChildConda
|
|
| ^^^^^^^^^^
|
|
4 | from package1 import WorkingVenv
|
|
5 | from package1 import BaseConda
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX and CONDA_DEFAULT_ENV (unequal) and VIRTUAL_ENV set,
|
|
// should find child active venv
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda-env"))
|
|
.env("CONDA_DEFAULT_ENV", "base")
|
|
.env("VIRTUAL_ENV", case.root().join("myvenv")), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `ActiveVenv`
|
|
--> test.py:2:22
|
|
|
|
|
2 | from package1 import ActiveVenv
|
|
| ^^^^^^^^^^
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
// run with CONDA_PREFIX and CONDA_DEFAULT_ENV (equal!) set, should find base conda
|
|
assert_cmd_snapshot!(case.command()
|
|
.current_dir(case.root().join("project"))
|
|
.env("CONDA_PREFIX", case.root().join("conda/envs/base"))
|
|
.env("CONDA_DEFAULT_ENV", "base"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Module `package1` has no member `BaseConda`
|
|
--> test.py:5:22
|
|
|
|
|
3 | from package1 import ChildConda
|
|
4 | from package1 import WorkingVenv
|
|
5 | from package1 import BaseConda
|
|
| ^^^^^^^^^
|
|
|
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn src_root_deprecation_warning() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.src]
|
|
root = "./src"
|
|
"#,
|
|
),
|
|
("src/test.py", ""),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
warning[deprecated-setting]: The `src.root` setting is deprecated. Use `environment.root` instead.
|
|
--> pyproject.toml:3:8
|
|
|
|
|
2 | [tool.ty.src]
|
|
3 | root = "./src"
|
|
| ^^^^^^^
|
|
|
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn src_root_deprecation_warning_with_environment_root() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.src]
|
|
root = "./src"
|
|
|
|
[tool.ty.environment]
|
|
root = ["./app"]
|
|
"#,
|
|
),
|
|
("app/test.py", ""),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
warning[deprecated-setting]: The `src.root` setting is deprecated. Use `environment.root` instead.
|
|
--> pyproject.toml:3:8
|
|
|
|
|
2 | [tool.ty.src]
|
|
3 | root = "./src"
|
|
| ^^^^^^^
|
|
4 |
|
|
5 | [tool.ty.environment]
|
|
|
|
|
info: The `src.root` setting was ignored in favor of the `environment.root` setting
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn environment_root_takes_precedence_over_src_root() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[tool.ty.src]
|
|
root = "./src"
|
|
|
|
[tool.ty.environment]
|
|
root = ["./app"]
|
|
"#,
|
|
),
|
|
("src/test.py", "import my_module"),
|
|
(
|
|
"app/my_module.py",
|
|
"# This module exists in app/ but not src/",
|
|
),
|
|
])?;
|
|
|
|
// The test should pass because environment.root points to ./app where my_module.py exists
|
|
// If src.root took precedence, it would fail because my_module.py doesn't exist in ./src
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
warning[deprecated-setting]: The `src.root` setting is deprecated. Use `environment.root` instead.
|
|
--> pyproject.toml:3:8
|
|
|
|
|
2 | [tool.ty.src]
|
|
3 | root = "./src"
|
|
| ^^^^^^^
|
|
4 |
|
|
5 | [tool.ty.environment]
|
|
|
|
|
info: The `src.root` setting was ignored in favor of the `environment.root` setting
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn default_root_src_layout() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("src/foo.py", "foo = 10"),
|
|
("bar.py", "bar = 20"),
|
|
(
|
|
"src/main.py",
|
|
r#"
|
|
from foo import foo
|
|
from bar import bar
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn default_root_project_name_folder() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
(
|
|
"pyproject.toml",
|
|
r#"
|
|
[project]
|
|
name = "psycopg"
|
|
"#,
|
|
),
|
|
("psycopg/psycopg/foo.py", "foo = 10"),
|
|
("bar.py", "bar = 20"),
|
|
(
|
|
"psycopg/psycopg/main.py",
|
|
r#"
|
|
from psycopg.foo import foo
|
|
from bar import bar
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn default_root_flat_layout() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("app/foo.py", "foo = 10"),
|
|
("bar.py", "bar = 20"),
|
|
(
|
|
"app/main.py",
|
|
r#"
|
|
from app.foo import foo
|
|
from bar import bar
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn default_root_tests_folder() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("src/foo.py", "foo = 10"),
|
|
("tests/bar.py", "bar = 20"),
|
|
(
|
|
"tests/test_bar.py",
|
|
r#"
|
|
from foo import foo
|
|
from bar import bar
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// If `tests/__init__.py` is present, it is considered a package and `tests` is not added to `sys.path`.
|
|
#[test]
|
|
fn default_root_tests_package() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("src/foo.py", "foo = 10"),
|
|
("tests/__init__.py", ""),
|
|
("tests/bar.py", "bar = 20"),
|
|
(
|
|
"tests/test_bar.py",
|
|
r#"
|
|
from foo import foo
|
|
from bar import bar # expected unresolved import
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `bar`
|
|
--> tests/test_bar.py:3:6
|
|
|
|
|
2 | from foo import foo
|
|
3 | from bar import bar # expected unresolved import
|
|
| ^^^
|
|
4 |
|
|
5 | print(f"{foo} {bar}")
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/src (first-party code)
|
|
info: 2. <temp_dir>/ (first-party code)
|
|
info: 3. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn default_root_python_folder() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("src/foo.py", "foo = 10"),
|
|
("python/bar.py", "bar = 20"),
|
|
(
|
|
"python/test_bar.py",
|
|
r#"
|
|
from foo import foo
|
|
from bar import bar
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// If `python/__init__.py` is present, it is considered a package and `python` is not added to search paths.
|
|
#[test]
|
|
fn default_root_python_package() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("src/foo.py", "foo = 10"),
|
|
("python/__init__.py", ""),
|
|
("python/bar.py", "bar = 20"),
|
|
(
|
|
"python/test_bar.py",
|
|
r#"
|
|
from foo import foo
|
|
from bar import bar # expected unresolved import
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `bar`
|
|
--> python/test_bar.py:3:6
|
|
|
|
|
2 | from foo import foo
|
|
3 | from bar import bar # expected unresolved import
|
|
| ^^^
|
|
4 |
|
|
5 | print(f"{foo} {bar}")
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/src (first-party code)
|
|
info: 2. <temp_dir>/ (first-party code)
|
|
info: 3. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Similarly, if `python/__init__.pyi` is present, it is considered a package and `python` is not added to search paths.
|
|
#[test]
|
|
fn default_root_python_package_pyi() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("src/foo.py", "foo = 10"),
|
|
("python/__init__.pyi", ""),
|
|
("python/bar.py", "bar = 20"),
|
|
(
|
|
"python/test_bar.py",
|
|
r#"
|
|
from foo import foo
|
|
from bar import bar # expected unresolved import
|
|
|
|
print(f"{foo} {bar}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(), @r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `bar`
|
|
--> python/test_bar.py:3:6
|
|
|
|
|
2 | from foo import foo
|
|
3 | from bar import bar # expected unresolved import
|
|
| ^^^
|
|
4 |
|
|
5 | print(f"{foo} {bar}")
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/src (first-party code)
|
|
info: 2. <temp_dir>/ (first-party code)
|
|
info: 3. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn pythonpath_is_respected() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("baz-dir/baz.py", "it = 42"),
|
|
(
|
|
"src/foo.py",
|
|
r#"
|
|
import baz
|
|
print(f"{baz.it}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(),
|
|
@r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `baz`
|
|
--> src/foo.py:2:8
|
|
|
|
|
2 | import baz
|
|
| ^^^
|
|
3 | print(f"{baz.it}")
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/src (first-party code)
|
|
info: 2. <temp_dir>/ (first-party code)
|
|
info: 3. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 1 diagnostic
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
assert_cmd_snapshot!(case.command()
|
|
.env("PYTHONPATH", case.root().join("baz-dir")),
|
|
@r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn pythonpath_multiple_dirs_is_respected() -> anyhow::Result<()> {
|
|
let case = CliTest::with_files([
|
|
("baz-dir/baz.py", "it = 42"),
|
|
("foo-dir/foo.py", "it = 42"),
|
|
(
|
|
"src/main.py",
|
|
r#"
|
|
import baz
|
|
import foo
|
|
|
|
print(f"{baz.it}")
|
|
print(f"{foo.it}")
|
|
"#,
|
|
),
|
|
])?;
|
|
|
|
assert_cmd_snapshot!(case.command(),
|
|
@r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
error[unresolved-import]: Cannot resolve imported module `baz`
|
|
--> src/main.py:2:8
|
|
|
|
|
2 | import baz
|
|
| ^^^
|
|
3 | import foo
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/src (first-party code)
|
|
info: 2. <temp_dir>/ (first-party code)
|
|
info: 3. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
error[unresolved-import]: Cannot resolve imported module `foo`
|
|
--> src/main.py:3:8
|
|
|
|
|
2 | import baz
|
|
3 | import foo
|
|
| ^^^
|
|
4 |
|
|
5 | print(f"{baz.it}")
|
|
|
|
|
info: Searched in the following paths during module resolution:
|
|
info: 1. <temp_dir>/src (first-party code)
|
|
info: 2. <temp_dir>/ (first-party code)
|
|
info: 3. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
|
info: rule `unresolved-import` is enabled by default
|
|
|
|
Found 2 diagnostics
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
let pythonpath =
|
|
std::env::join_paths([case.root().join("baz-dir"), case.root().join("foo-dir")])?;
|
|
assert_cmd_snapshot!(case.command()
|
|
.env("PYTHONPATH", pythonpath),
|
|
@r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
All checks passed!
|
|
|
|
----- stderr -----
|
|
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|