mirror of https://github.com/astral-sh/ruff
[red-knot] Use a distinct type for module search paths in the module resolver (#12379)
This commit is contained in:
parent
ea2d51c2bb
commit
2a8f95c437
|
|
@ -5,7 +5,7 @@ use ruff_db::files::File;
|
||||||
|
|
||||||
use crate::db::Db;
|
use crate::db::Db;
|
||||||
use crate::module_name::ModuleName;
|
use crate::module_name::ModuleName;
|
||||||
use crate::path::{ModuleResolutionPathBuf, ModuleResolutionPathRef};
|
use crate::path::ModuleSearchPath;
|
||||||
|
|
||||||
/// Representation of a Python module.
|
/// Representation of a Python module.
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
|
@ -17,7 +17,7 @@ impl Module {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
name: ModuleName,
|
name: ModuleName,
|
||||||
kind: ModuleKind,
|
kind: ModuleKind,
|
||||||
search_path: Arc<ModuleResolutionPathBuf>,
|
search_path: ModuleSearchPath,
|
||||||
file: File,
|
file: File,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -41,8 +41,8 @@ impl Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The search path from which the module was resolved.
|
/// The search path from which the module was resolved.
|
||||||
pub(crate) fn search_path(&self) -> ModuleResolutionPathRef {
|
pub(crate) fn search_path(&self) -> &ModuleSearchPath {
|
||||||
ModuleResolutionPathRef::from(&*self.inner.search_path)
|
&self.inner.search_path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether this module is a single-file module or a package
|
/// Determine whether this module is a single-file module or a package
|
||||||
|
|
@ -77,7 +77,7 @@ impl salsa::DebugWithDb<dyn Db> for Module {
|
||||||
struct ModuleInner {
|
struct ModuleInner {
|
||||||
name: ModuleName,
|
name: ModuleName,
|
||||||
kind: ModuleKind,
|
kind: ModuleKind,
|
||||||
search_path: Arc<ModuleResolutionPathBuf>,
|
search_path: ModuleSearchPath,
|
||||||
file: File,
|
file: File,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
//! <https://github.com/astral-sh/ruff/pull/12141#discussion_r1667010245>
|
//! <https://github.com/astral-sh/ruff/pull/12141#discussion_r1667010245>
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ruff_db::files::{system_path_to_file, vendored_path_to_file, File, FilePath};
|
use ruff_db::files::{system_path_to_file, vendored_path_to_file, File, FilePath};
|
||||||
use ruff_db::system::{System, SystemPath, SystemPathBuf};
|
use ruff_db::system::{System, SystemPath, SystemPathBuf};
|
||||||
|
|
@ -68,7 +70,7 @@ impl<'a> From<&'a FilePath> for FilePathRef<'a> {
|
||||||
///
|
///
|
||||||
/// [the order given in the typing spec]: https://typing.readthedocs.io/en/latest/spec/distributing.html#import-resolution-ordering
|
/// [the order given in the typing spec]: https://typing.readthedocs.io/en/latest/spec/distributing.html#import-resolution-ordering
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
enum ModuleResolutionPathBufInner {
|
enum ModulePathBufInner {
|
||||||
Extra(SystemPathBuf),
|
Extra(SystemPathBuf),
|
||||||
FirstParty(SystemPathBuf),
|
FirstParty(SystemPathBuf),
|
||||||
StandardLibrary(FilePath),
|
StandardLibrary(FilePath),
|
||||||
|
|
@ -76,7 +78,7 @@ enum ModuleResolutionPathBufInner {
|
||||||
EditableInstall(SystemPathBuf),
|
EditableInstall(SystemPathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleResolutionPathBufInner {
|
impl ModulePathBufInner {
|
||||||
fn push(&mut self, component: &str) {
|
fn push(&mut self, component: &str) {
|
||||||
let extension = camino::Utf8Path::new(component).extension();
|
let extension = camino::Utf8Path::new(component).extension();
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -153,9 +155,9 @@ impl ModuleResolutionPathBufInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct ModuleResolutionPathBuf(ModuleResolutionPathBufInner);
|
pub(crate) struct ModulePathBuf(ModulePathBufInner);
|
||||||
|
|
||||||
impl ModuleResolutionPathBuf {
|
impl ModulePathBuf {
|
||||||
/// Push a new part to the path,
|
/// Push a new part to the path,
|
||||||
/// while maintaining the invariant that the path can only have `.py` or `.pyi` extensions.
|
/// while maintaining the invariant that the path can only have `.py` or `.pyi` extensions.
|
||||||
/// For the stdlib variant specifically, it may only have a `.pyi` extension.
|
/// For the stdlib variant specifically, it may only have a `.pyi` extension.
|
||||||
|
|
@ -171,7 +173,7 @@ impl ModuleResolutionPathBuf {
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
path.extension()
|
path.extension()
|
||||||
.map_or(true, |ext| matches!(ext, "py" | "pyi"))
|
.map_or(true, |ext| matches!(ext, "py" | "pyi"))
|
||||||
.then_some(Self(ModuleResolutionPathBufInner::Extra(path)))
|
.then_some(Self(ModulePathBufInner::Extra(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -179,28 +181,14 @@ impl ModuleResolutionPathBuf {
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
path.extension()
|
path.extension()
|
||||||
.map_or(true, |ext| matches!(ext, "pyi" | "py"))
|
.map_or(true, |ext| matches!(ext, "pyi" | "py"))
|
||||||
.then_some(Self(ModuleResolutionPathBufInner::FirstParty(path)))
|
.then_some(Self(ModulePathBufInner::FirstParty(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn standard_library(path: FilePath) -> Option<Self> {
|
pub(crate) fn standard_library(path: FilePath) -> Option<Self> {
|
||||||
path.extension()
|
path.extension()
|
||||||
.map_or(true, |ext| ext == "pyi")
|
.map_or(true, |ext| ext == "pyi")
|
||||||
.then_some(Self(ModuleResolutionPathBufInner::StandardLibrary(path)))
|
.then_some(Self(ModulePathBufInner::StandardLibrary(path)))
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub(crate) fn stdlib_from_custom_typeshed_root(typeshed_root: &SystemPath) -> Option<Self> {
|
|
||||||
Self::standard_library(FilePath::System(
|
|
||||||
typeshed_root.join(SystemPath::new("stdlib")),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub(crate) fn vendored_stdlib() -> Self {
|
|
||||||
Self(ModuleResolutionPathBufInner::StandardLibrary(
|
|
||||||
FilePath::Vendored(VendoredPathBuf::from("stdlib")),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -208,7 +196,7 @@ impl ModuleResolutionPathBuf {
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
path.extension()
|
path.extension()
|
||||||
.map_or(true, |ext| matches!(ext, "pyi" | "py"))
|
.map_or(true, |ext| matches!(ext, "pyi" | "py"))
|
||||||
.then_some(Self(ModuleResolutionPathBufInner::SitePackages(path)))
|
.then_some(Self(ModulePathBufInner::SitePackages(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -220,104 +208,115 @@ impl ModuleResolutionPathBuf {
|
||||||
// TODO: Add Salsa invalidation to this system call:
|
// TODO: Add Salsa invalidation to this system call:
|
||||||
system
|
system
|
||||||
.is_directory(&path)
|
.is_directory(&path)
|
||||||
.then_some(Self(ModuleResolutionPathBufInner::EditableInstall(path)))
|
.then_some(Self(ModulePathBufInner::EditableInstall(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn is_regular_package(&self, search_path: &Self, resolver: &ResolverState) -> bool {
|
pub(crate) fn is_regular_package(&self, search_path: &Self, resolver: &ResolverState) -> bool {
|
||||||
ModuleResolutionPathRef::from(self).is_regular_package(search_path, resolver)
|
ModulePathRef::from(self).is_regular_package(search_path, resolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn is_directory(&self, search_path: &Self, resolver: &ResolverState) -> bool {
|
pub(crate) fn is_directory(&self, search_path: &Self, resolver: &ResolverState) -> bool {
|
||||||
ModuleResolutionPathRef::from(self).is_directory(search_path, resolver)
|
ModulePathRef::from(self).is_directory(search_path, resolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) const fn is_site_packages(&self) -> bool {
|
pub(crate) const fn is_site_packages(&self) -> bool {
|
||||||
matches!(self.0, ModuleResolutionPathBufInner::SitePackages(_))
|
matches!(self.0, ModulePathBufInner::SitePackages(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) const fn is_standard_library(&self) -> bool {
|
pub(crate) const fn is_standard_library(&self) -> bool {
|
||||||
matches!(self.0, ModuleResolutionPathBufInner::StandardLibrary(_))
|
matches!(self.0, ModulePathBufInner::StandardLibrary(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn with_pyi_extension(&self) -> Self {
|
pub(crate) fn with_pyi_extension(&self) -> Self {
|
||||||
ModuleResolutionPathRef::from(self).with_pyi_extension()
|
ModulePathRef::from(self).with_pyi_extension()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn with_py_extension(&self) -> Option<Self> {
|
pub(crate) fn with_py_extension(&self) -> Option<Self> {
|
||||||
ModuleResolutionPathRef::from(self).with_py_extension()
|
ModulePathRef::from(self).with_py_extension()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn relativize_path<'a>(
|
pub(crate) fn relativize_path<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
absolute_path: &'a FilePath,
|
absolute_path: &'a FilePath,
|
||||||
) -> Option<ModuleResolutionPathRef<'a>> {
|
) -> Option<ModulePathRef<'a>> {
|
||||||
ModuleResolutionPathRef::from(self).relativize_path(&FilePathRef::from(absolute_path))
|
ModulePathRef::from(self).relativize_path(&FilePathRef::from(absolute_path))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `None` if the path doesn't exist, isn't accessible, or if the path points to a directory.
|
/// Returns `None` if the path doesn't exist, isn't accessible, or if the path points to a directory.
|
||||||
pub(crate) fn to_file(&self, search_path: &Self, resolver: &ResolverState) -> Option<File> {
|
pub(crate) fn to_file(&self, search_path: &Self, resolver: &ResolverState) -> Option<File> {
|
||||||
ModuleResolutionPathRef::from(self).to_file(search_path, resolver)
|
ModulePathRef::from(self).to_file(search_path, resolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn as_system_path(&self) -> Option<&SystemPathBuf> {
|
pub(crate) fn as_system_path(&self) -> Option<&SystemPathBuf> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
ModuleResolutionPathBufInner::Extra(path) => Some(path),
|
ModulePathBufInner::Extra(path) => Some(path),
|
||||||
ModuleResolutionPathBufInner::FirstParty(path) => Some(path),
|
ModulePathBufInner::FirstParty(path) => Some(path),
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(_) => None,
|
ModulePathBufInner::StandardLibrary(_) => None,
|
||||||
ModuleResolutionPathBufInner::SitePackages(path) => Some(path),
|
ModulePathBufInner::SitePackages(path) => Some(path),
|
||||||
ModuleResolutionPathBufInner::EditableInstall(path) => Some(path),
|
ModulePathBufInner::EditableInstall(path) => Some(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ModuleResolutionPathBuf {
|
impl fmt::Debug for ModulePathBuf {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
ModuleResolutionPathBufInner::Extra(path) => f
|
ModulePathBufInner::Extra(path) => {
|
||||||
.debug_tuple("ModuleResolutionPathBuf::Extra")
|
f.debug_tuple("ModulePathBuf::Extra").field(path).finish()
|
||||||
|
}
|
||||||
|
ModulePathBufInner::FirstParty(path) => f
|
||||||
|
.debug_tuple("ModulePathBuf::FirstParty")
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
ModuleResolutionPathBufInner::FirstParty(path) => f
|
ModulePathBufInner::SitePackages(path) => f
|
||||||
.debug_tuple("ModuleResolutionPathBuf::FirstParty")
|
.debug_tuple("ModulePathBuf::SitePackages")
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
ModuleResolutionPathBufInner::SitePackages(path) => f
|
ModulePathBufInner::StandardLibrary(path) => f
|
||||||
.debug_tuple("ModuleResolutionPathBuf::SitePackages")
|
.debug_tuple("ModulePathBuf::StandardLibrary")
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(path) => f
|
ModulePathBufInner::EditableInstall(path) => f
|
||||||
.debug_tuple("ModuleResolutionPathBuf::StandardLibrary")
|
.debug_tuple("ModulePathBuf::EditableInstall")
|
||||||
.field(path)
|
|
||||||
.finish(),
|
|
||||||
ModuleResolutionPathBufInner::EditableInstall(path) => f
|
|
||||||
.debug_tuple("ModuleResolutionPathBuf::EditableInstall")
|
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<SystemPathBuf> for ModuleResolutionPathBuf {
|
impl PartialEq<SystemPathBuf> for ModulePathBuf {
|
||||||
fn eq(&self, other: &SystemPathBuf) -> bool {
|
fn eq(&self, other: &SystemPathBuf) -> bool {
|
||||||
ModuleResolutionPathRef::from(self) == **other
|
ModulePathRef::from(self) == **other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<ModuleResolutionPathBuf> for SystemPathBuf {
|
impl PartialEq<ModulePathBuf> for SystemPathBuf {
|
||||||
fn eq(&self, other: &ModuleResolutionPathBuf) -> bool {
|
fn eq(&self, other: &ModulePathBuf) -> bool {
|
||||||
|
other.eq(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<VendoredPathBuf> for ModulePathBuf {
|
||||||
|
fn eq(&self, other: &VendoredPathBuf) -> bool {
|
||||||
|
ModulePathRef::from(self) == **other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<ModulePathBuf> for VendoredPathBuf {
|
||||||
|
fn eq(&self, other: &ModulePathBuf) -> bool {
|
||||||
other.eq(self)
|
other.eq(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
enum ModuleResolutionPathRefInner<'a> {
|
enum ModulePathRefInner<'a> {
|
||||||
Extra(&'a SystemPath),
|
Extra(&'a SystemPath),
|
||||||
FirstParty(&'a SystemPath),
|
FirstParty(&'a SystemPath),
|
||||||
StandardLibrary(FilePathRef<'a>),
|
StandardLibrary(FilePathRef<'a>),
|
||||||
|
|
@ -325,7 +324,7 @@ enum ModuleResolutionPathRefInner<'a> {
|
||||||
EditableInstall(&'a SystemPath),
|
EditableInstall(&'a SystemPath),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ModuleResolutionPathRefInner<'a> {
|
impl<'a> ModulePathRefInner<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn query_stdlib_version<'db>(
|
fn query_stdlib_version<'db>(
|
||||||
module_path: &FilePathRef<'a>,
|
module_path: &FilePathRef<'a>,
|
||||||
|
|
@ -463,45 +462,37 @@ impl<'a> ModuleResolutionPathRefInner<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn with_pyi_extension(&self) -> ModuleResolutionPathBufInner {
|
fn with_pyi_extension(&self) -> ModulePathBufInner {
|
||||||
match self {
|
match self {
|
||||||
Self::Extra(path) => ModuleResolutionPathBufInner::Extra(path.with_extension("pyi")),
|
Self::Extra(path) => ModulePathBufInner::Extra(path.with_extension("pyi")),
|
||||||
Self::FirstParty(path) => {
|
Self::FirstParty(path) => ModulePathBufInner::FirstParty(path.with_extension("pyi")),
|
||||||
ModuleResolutionPathBufInner::FirstParty(path.with_extension("pyi"))
|
|
||||||
}
|
|
||||||
Self::StandardLibrary(FilePathRef::System(path)) => {
|
Self::StandardLibrary(FilePathRef::System(path)) => {
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(FilePath::System(
|
ModulePathBufInner::StandardLibrary(FilePath::System(path.with_extension("pyi")))
|
||||||
path.with_extension("pyi"),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Self::StandardLibrary(FilePathRef::Vendored(path)) => {
|
Self::StandardLibrary(FilePathRef::Vendored(path)) => {
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(FilePath::Vendored(
|
ModulePathBufInner::StandardLibrary(FilePath::Vendored(path.with_pyi_extension()))
|
||||||
path.with_pyi_extension(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Self::SitePackages(path) => {
|
Self::SitePackages(path) => {
|
||||||
ModuleResolutionPathBufInner::SitePackages(path.with_extension("pyi"))
|
ModulePathBufInner::SitePackages(path.with_extension("pyi"))
|
||||||
}
|
}
|
||||||
Self::EditableInstall(path) => {
|
Self::EditableInstall(path) => {
|
||||||
ModuleResolutionPathBufInner::EditableInstall(path.with_extension("pyi"))
|
ModulePathBufInner::EditableInstall(path.with_extension("pyi"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn with_py_extension(&self) -> Option<ModuleResolutionPathBufInner> {
|
fn with_py_extension(&self) -> Option<ModulePathBufInner> {
|
||||||
match self {
|
match self {
|
||||||
Self::Extra(path) => Some(ModuleResolutionPathBufInner::Extra(
|
Self::Extra(path) => Some(ModulePathBufInner::Extra(path.with_extension("py"))),
|
||||||
path.with_extension("py"),
|
Self::FirstParty(path) => {
|
||||||
)),
|
Some(ModulePathBufInner::FirstParty(path.with_extension("py")))
|
||||||
Self::FirstParty(path) => Some(ModuleResolutionPathBufInner::FirstParty(
|
}
|
||||||
path.with_extension("py"),
|
|
||||||
)),
|
|
||||||
Self::StandardLibrary(_) => None,
|
Self::StandardLibrary(_) => None,
|
||||||
Self::SitePackages(path) => Some(ModuleResolutionPathBufInner::SitePackages(
|
Self::SitePackages(path) => {
|
||||||
path.with_extension("py"),
|
Some(ModulePathBufInner::SitePackages(path.with_extension("py")))
|
||||||
)),
|
}
|
||||||
Self::EditableInstall(path) => Some(ModuleResolutionPathBufInner::EditableInstall(
|
Self::EditableInstall(path) => Some(ModulePathBufInner::EditableInstall(
|
||||||
path.with_extension("py"),
|
path.with_extension("py"),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
@ -567,9 +558,9 @@ impl<'a> ModuleResolutionPathRefInner<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) struct ModuleResolutionPathRef<'a>(ModuleResolutionPathRefInner<'a>);
|
pub(crate) struct ModulePathRef<'a>(ModulePathRefInner<'a>);
|
||||||
|
|
||||||
impl<'a> ModuleResolutionPathRef<'a> {
|
impl<'a> ModulePathRef<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn is_directory(
|
pub(crate) fn is_directory(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -603,13 +594,13 @@ impl<'a> ModuleResolutionPathRef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn with_pyi_extension(&self) -> ModuleResolutionPathBuf {
|
pub(crate) fn with_pyi_extension(&self) -> ModulePathBuf {
|
||||||
ModuleResolutionPathBuf(self.0.with_pyi_extension())
|
ModulePathBuf(self.0.with_pyi_extension())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn with_py_extension(self) -> Option<ModuleResolutionPathBuf> {
|
pub(crate) fn with_py_extension(self) -> Option<ModulePathBuf> {
|
||||||
self.0.with_py_extension().map(ModuleResolutionPathBuf)
|
self.0.with_py_extension().map(ModulePathBuf)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -618,123 +609,188 @@ impl<'a> ModuleResolutionPathRef<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ModuleResolutionPathRef<'_> {
|
impl fmt::Debug for ModulePathRef<'_> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
ModuleResolutionPathRefInner::Extra(path) => f
|
ModulePathRefInner::Extra(path) => {
|
||||||
.debug_tuple("ModuleResolutionPathRef::Extra")
|
f.debug_tuple("ModulePathRef::Extra").field(path).finish()
|
||||||
|
}
|
||||||
|
ModulePathRefInner::FirstParty(path) => f
|
||||||
|
.debug_tuple("ModulePathRef::FirstParty")
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
ModuleResolutionPathRefInner::FirstParty(path) => f
|
ModulePathRefInner::SitePackages(path) => f
|
||||||
.debug_tuple("ModuleResolutionPathRef::FirstParty")
|
.debug_tuple("ModulePathRef::SitePackages")
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
ModuleResolutionPathRefInner::SitePackages(path) => f
|
ModulePathRefInner::StandardLibrary(path) => f
|
||||||
.debug_tuple("ModuleResolutionPathRef::SitePackages")
|
.debug_tuple("ModulePathRef::StandardLibrary")
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(path) => f
|
ModulePathRefInner::EditableInstall(path) => f
|
||||||
.debug_tuple("ModuleResolutionPathRef::StandardLibrary")
|
.debug_tuple("ModulePathRef::EditableInstall")
|
||||||
.field(path)
|
|
||||||
.finish(),
|
|
||||||
ModuleResolutionPathRefInner::EditableInstall(path) => f
|
|
||||||
.debug_tuple("ModuleResolutionPathRef::EditableInstall")
|
|
||||||
.field(path)
|
.field(path)
|
||||||
.finish(),
|
.finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ModuleResolutionPathBuf> for ModuleResolutionPathRef<'a> {
|
impl<'a> From<&'a ModulePathBuf> for ModulePathRef<'a> {
|
||||||
fn from(value: &'a ModuleResolutionPathBuf) -> Self {
|
fn from(value: &'a ModulePathBuf) -> Self {
|
||||||
let inner = match &value.0 {
|
let inner = match &value.0 {
|
||||||
ModuleResolutionPathBufInner::Extra(path) => ModuleResolutionPathRefInner::Extra(path),
|
ModulePathBufInner::Extra(path) => ModulePathRefInner::Extra(path),
|
||||||
ModuleResolutionPathBufInner::FirstParty(path) => {
|
ModulePathBufInner::FirstParty(path) => ModulePathRefInner::FirstParty(path),
|
||||||
ModuleResolutionPathRefInner::FirstParty(path)
|
ModulePathBufInner::StandardLibrary(FilePath::System(path)) => {
|
||||||
|
ModulePathRefInner::StandardLibrary(FilePathRef::System(path))
|
||||||
}
|
}
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(FilePath::System(path)) => {
|
ModulePathBufInner::StandardLibrary(FilePath::Vendored(path)) => {
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(path))
|
ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(path))
|
||||||
}
|
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(FilePath::Vendored(path)) => {
|
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(path))
|
|
||||||
}
|
|
||||||
ModuleResolutionPathBufInner::SitePackages(path) => {
|
|
||||||
ModuleResolutionPathRefInner::SitePackages(path)
|
|
||||||
}
|
|
||||||
ModuleResolutionPathBufInner::EditableInstall(path) => {
|
|
||||||
ModuleResolutionPathRefInner::EditableInstall(path)
|
|
||||||
}
|
}
|
||||||
|
ModulePathBufInner::SitePackages(path) => ModulePathRefInner::SitePackages(path),
|
||||||
|
ModulePathBufInner::EditableInstall(path) => ModulePathRefInner::EditableInstall(path),
|
||||||
};
|
};
|
||||||
ModuleResolutionPathRef(inner)
|
ModulePathRef(inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<SystemPath> for ModuleResolutionPathRef<'_> {
|
impl PartialEq<SystemPath> for ModulePathRef<'_> {
|
||||||
fn eq(&self, other: &SystemPath) -> bool {
|
fn eq(&self, other: &SystemPath) -> bool {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
ModuleResolutionPathRefInner::Extra(path) => path == other,
|
ModulePathRefInner::Extra(path) => path == other,
|
||||||
ModuleResolutionPathRefInner::FirstParty(path) => path == other,
|
ModulePathRefInner::FirstParty(path) => path == other,
|
||||||
ModuleResolutionPathRefInner::SitePackages(path) => path == other,
|
ModulePathRefInner::SitePackages(path) => path == other,
|
||||||
ModuleResolutionPathRefInner::EditableInstall(path) => path == other,
|
ModulePathRefInner::EditableInstall(path) => path == other,
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(path)) => {
|
ModulePathRefInner::StandardLibrary(FilePathRef::System(path)) => path == other,
|
||||||
path == other
|
ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(_)) => false,
|
||||||
}
|
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(_)) => false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<ModuleResolutionPathRef<'_>> for SystemPath {
|
impl PartialEq<ModulePathRef<'_>> for SystemPath {
|
||||||
fn eq(&self, other: &ModuleResolutionPathRef) -> bool {
|
fn eq(&self, other: &ModulePathRef) -> bool {
|
||||||
other == self
|
other == self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<SystemPathBuf> for ModuleResolutionPathRef<'_> {
|
impl PartialEq<SystemPathBuf> for ModulePathRef<'_> {
|
||||||
fn eq(&self, other: &SystemPathBuf) -> bool {
|
fn eq(&self, other: &SystemPathBuf) -> bool {
|
||||||
self == &**other
|
self == &**other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<ModuleResolutionPathRef<'_>> for SystemPathBuf {
|
impl PartialEq<ModulePathRef<'_>> for SystemPathBuf {
|
||||||
fn eq(&self, other: &ModuleResolutionPathRef<'_>) -> bool {
|
fn eq(&self, other: &ModulePathRef<'_>) -> bool {
|
||||||
&**self == other
|
&**self == other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<VendoredPath> for ModuleResolutionPathRef<'_> {
|
impl PartialEq<VendoredPath> for ModulePathRef<'_> {
|
||||||
fn eq(&self, other: &VendoredPath) -> bool {
|
fn eq(&self, other: &VendoredPath) -> bool {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
ModuleResolutionPathRefInner::Extra(_) => false,
|
ModulePathRefInner::Extra(_) => false,
|
||||||
ModuleResolutionPathRefInner::FirstParty(_) => false,
|
ModulePathRefInner::FirstParty(_) => false,
|
||||||
ModuleResolutionPathRefInner::SitePackages(_) => false,
|
ModulePathRefInner::SitePackages(_) => false,
|
||||||
ModuleResolutionPathRefInner::EditableInstall(_) => false,
|
ModulePathRefInner::EditableInstall(_) => false,
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(_)) => false,
|
ModulePathRefInner::StandardLibrary(FilePathRef::System(_)) => false,
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => {
|
ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => path == other,
|
||||||
path == other
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<ModuleResolutionPathRef<'_>> for VendoredPath {
|
impl PartialEq<ModulePathRef<'_>> for VendoredPath {
|
||||||
fn eq(&self, other: &ModuleResolutionPathRef) -> bool {
|
fn eq(&self, other: &ModulePathRef) -> bool {
|
||||||
other == self
|
other == self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<VendoredPathBuf> for ModuleResolutionPathRef<'_> {
|
impl PartialEq<VendoredPathBuf> for ModulePathRef<'_> {
|
||||||
fn eq(&self, other: &VendoredPathBuf) -> bool {
|
fn eq(&self, other: &VendoredPathBuf) -> bool {
|
||||||
self == &**other
|
self == &**other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<ModuleResolutionPathRef<'_>> for VendoredPathBuf {
|
impl PartialEq<ModulePathRef<'_>> for VendoredPathBuf {
|
||||||
fn eq(&self, other: &ModuleResolutionPathRef<'_>) -> bool {
|
fn eq(&self, other: &ModulePathRef<'_>) -> bool {
|
||||||
&**self == other
|
&**self == other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub(crate) struct ModuleSearchPath(Arc<ModulePathBuf>);
|
||||||
|
|
||||||
|
impl ModuleSearchPath {
|
||||||
|
pub(crate) fn extra(path: SystemPathBuf) -> Option<Self> {
|
||||||
|
Some(Self(Arc::new(ModulePathBuf::extra(path)?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn first_party(path: SystemPathBuf) -> Option<Self> {
|
||||||
|
Some(Self(Arc::new(ModulePathBuf::first_party(path)?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn custom_stdlib(path: &SystemPath) -> Option<Self> {
|
||||||
|
Some(Self(Arc::new(ModulePathBuf::standard_library(
|
||||||
|
FilePath::System(path.join("stdlib")),
|
||||||
|
)?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn vendored_stdlib() -> Self {
|
||||||
|
Self(Arc::new(ModulePathBuf(
|
||||||
|
ModulePathBufInner::StandardLibrary(FilePath::Vendored(VendoredPathBuf::from(
|
||||||
|
"stdlib",
|
||||||
|
))),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn site_packages(path: SystemPathBuf) -> Option<Self> {
|
||||||
|
Some(Self(Arc::new(ModulePathBuf::site_packages(path)?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn editable(system: &dyn System, path: SystemPathBuf) -> Option<Self> {
|
||||||
|
Some(Self(Arc::new(ModulePathBuf::editable_installation_root(
|
||||||
|
system, path,
|
||||||
|
)?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn as_module_path(&self) -> &ModulePathBuf {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<SystemPathBuf> for ModuleSearchPath {
|
||||||
|
fn eq(&self, other: &SystemPathBuf) -> bool {
|
||||||
|
&*self.0 == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<ModuleSearchPath> for SystemPathBuf {
|
||||||
|
fn eq(&self, other: &ModuleSearchPath) -> bool {
|
||||||
|
other.eq(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<VendoredPathBuf> for ModuleSearchPath {
|
||||||
|
fn eq(&self, other: &VendoredPathBuf) -> bool {
|
||||||
|
&*self.0 == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<ModuleSearchPath> for VendoredPathBuf {
|
||||||
|
fn eq(&self, other: &ModuleSearchPath) -> bool {
|
||||||
|
other.eq(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this is unprincipled.
|
||||||
|
// We should instead just implement the methods we need on ModuleSearchPath,
|
||||||
|
// and adjust the signatures/implementations of methods that receive ModuleSearchPaths.
|
||||||
|
impl Deref for ModuleSearchPath {
|
||||||
|
type Target = ModulePathBuf;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use insta::assert_debug_snapshot;
|
use insta::assert_debug_snapshot;
|
||||||
|
|
@ -751,67 +807,60 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleResolutionPathBuf {
|
impl ModulePathBuf {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn join(&self, component: &str) -> Self {
|
pub(crate) fn join(&self, component: &str) -> Self {
|
||||||
ModuleResolutionPathRef::from(self).join(component)
|
ModulePathRef::from(self).join(component)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ModuleResolutionPathRef<'a> {
|
impl<'a> ModulePathRef<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn join(
|
fn join(&self, component: &'a (impl AsRef<SystemPath> + ?Sized)) -> ModulePathBuf {
|
||||||
&self,
|
|
||||||
component: &'a (impl AsRef<SystemPath> + ?Sized),
|
|
||||||
) -> ModuleResolutionPathBuf {
|
|
||||||
let mut result = self.to_path_buf();
|
let mut result = self.to_path_buf();
|
||||||
result.push(component.as_ref().as_str());
|
result.push(component.as_ref().as_str());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn to_path_buf(self) -> ModuleResolutionPathBuf {
|
pub(crate) fn to_path_buf(self) -> ModulePathBuf {
|
||||||
let inner = match self.0 {
|
let inner = match self.0 {
|
||||||
ModuleResolutionPathRefInner::Extra(path) => {
|
ModulePathRefInner::Extra(path) => ModulePathBufInner::Extra(path.to_path_buf()),
|
||||||
ModuleResolutionPathBufInner::Extra(path.to_path_buf())
|
ModulePathRefInner::FirstParty(path) => {
|
||||||
|
ModulePathBufInner::FirstParty(path.to_path_buf())
|
||||||
}
|
}
|
||||||
ModuleResolutionPathRefInner::FirstParty(path) => {
|
ModulePathRefInner::StandardLibrary(FilePathRef::System(path)) => {
|
||||||
ModuleResolutionPathBufInner::FirstParty(path.to_path_buf())
|
ModulePathBufInner::StandardLibrary(FilePath::System(path.to_path_buf()))
|
||||||
}
|
}
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(path)) => {
|
ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => {
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(FilePath::System(
|
ModulePathBufInner::StandardLibrary(FilePath::Vendored(path.to_path_buf()))
|
||||||
path.to_path_buf(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => {
|
ModulePathRefInner::SitePackages(path) => {
|
||||||
ModuleResolutionPathBufInner::StandardLibrary(FilePath::Vendored(
|
ModulePathBufInner::SitePackages(path.to_path_buf())
|
||||||
path.to_path_buf(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
ModuleResolutionPathRefInner::SitePackages(path) => {
|
ModulePathRefInner::EditableInstall(path) => {
|
||||||
ModuleResolutionPathBufInner::SitePackages(path.to_path_buf())
|
ModulePathBufInner::EditableInstall(path.to_path_buf())
|
||||||
}
|
|
||||||
ModuleResolutionPathRefInner::EditableInstall(path) => {
|
|
||||||
ModuleResolutionPathBufInner::EditableInstall(path.to_path_buf())
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ModuleResolutionPathBuf(inner)
|
ModulePathBuf(inner)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleSearchPath {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) const fn is_stdlib_search_path(&self) -> bool {
|
pub(crate) fn is_stdlib_search_path(&self) -> bool {
|
||||||
matches!(&self.0, ModuleResolutionPathRefInner::StandardLibrary(_))
|
matches!(&self.0 .0, ModulePathBufInner::StandardLibrary(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn constructor_rejects_non_pyi_stdlib_paths() {
|
fn constructor_rejects_non_pyi_stdlib_paths() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo.py")),
|
ModulePathBuf::standard_library(FilePath::system("foo.py")),
|
||||||
None
|
None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo/__init__.py")),
|
ModulePathBuf::standard_library(FilePath::system("foo/__init__.py")),
|
||||||
None
|
None
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -819,9 +868,9 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn path_buf_debug_impl() {
|
fn path_buf_debug_impl() {
|
||||||
assert_debug_snapshot!(
|
assert_debug_snapshot!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo/bar.pyi")).unwrap(),
|
ModulePathBuf::standard_library(FilePath::system("foo/bar.pyi")).unwrap(),
|
||||||
@r###"
|
@r###"
|
||||||
ModuleResolutionPathBuf::StandardLibrary(
|
ModulePathBuf::StandardLibrary(
|
||||||
System(
|
System(
|
||||||
"foo/bar.pyi",
|
"foo/bar.pyi",
|
||||||
),
|
),
|
||||||
|
|
@ -833,9 +882,9 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn path_ref_debug_impl() {
|
fn path_ref_debug_impl() {
|
||||||
assert_debug_snapshot!(
|
assert_debug_snapshot!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::Extra(SystemPath::new("foo/bar.py"))),
|
ModulePathRef(ModulePathRefInner::Extra(SystemPath::new("foo/bar.py"))),
|
||||||
@r###"
|
@r###"
|
||||||
ModuleResolutionPathRef::Extra(
|
ModulePathRef::Extra(
|
||||||
"foo/bar.py",
|
"foo/bar.py",
|
||||||
)
|
)
|
||||||
"###
|
"###
|
||||||
|
|
@ -845,50 +894,49 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn with_extension_methods() {
|
fn with_extension_methods() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo"))
|
ModulePathBuf::standard_library(FilePath::system("foo"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_py_extension(),
|
.with_py_extension(),
|
||||||
None
|
None
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo"))
|
ModulePathBuf::standard_library(FilePath::system("foo"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_pyi_extension(),
|
.with_pyi_extension(),
|
||||||
ModuleResolutionPathBuf(ModuleResolutionPathBufInner::StandardLibrary(
|
ModulePathBuf(ModulePathBufInner::StandardLibrary(FilePath::System(
|
||||||
FilePath::System(SystemPathBuf::from("foo.pyi"))
|
SystemPathBuf::from("foo.pyi")
|
||||||
))
|
)))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::first_party("foo/bar")
|
ModulePathBuf::first_party("foo/bar")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_py_extension()
|
.with_py_extension()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
ModuleResolutionPathBuf(ModuleResolutionPathBufInner::FirstParty(
|
ModulePathBuf(ModulePathBufInner::FirstParty(SystemPathBuf::from(
|
||||||
SystemPathBuf::from("foo/bar.py")
|
"foo/bar.py"
|
||||||
))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn module_name_1_part() {
|
fn module_name_1_part() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::Extra(SystemPath::new("foo")))
|
ModulePathRef(ModulePathRefInner::Extra(SystemPath::new("foo"))).to_module_name(),
|
||||||
.to_module_name(),
|
|
||||||
ModuleName::new_static("foo")
|
ModuleName::new_static("foo")
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::StandardLibrary(
|
ModulePathRef(ModulePathRefInner::StandardLibrary(FilePathRef::system(
|
||||||
FilePathRef::system("foo.pyi")
|
"foo.pyi"
|
||||||
))
|
)))
|
||||||
.to_module_name(),
|
.to_module_name(),
|
||||||
ModuleName::new_static("foo")
|
ModuleName::new_static("foo")
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::FirstParty(SystemPath::new(
|
ModulePathRef(ModulePathRefInner::FirstParty(SystemPath::new(
|
||||||
"foo/__init__.py"
|
"foo/__init__.py"
|
||||||
)))
|
)))
|
||||||
.to_module_name(),
|
.to_module_name(),
|
||||||
|
|
@ -899,23 +947,21 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn module_name_2_parts() {
|
fn module_name_2_parts() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::StandardLibrary(
|
ModulePathRef(ModulePathRefInner::StandardLibrary(FilePathRef::system(
|
||||||
FilePathRef::system("foo/bar")
|
"foo/bar"
|
||||||
))
|
|
||||||
.to_module_name(),
|
|
||||||
ModuleName::new_static("foo.bar")
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::Extra(SystemPath::new(
|
|
||||||
"foo/bar.pyi"
|
|
||||||
)))
|
)))
|
||||||
.to_module_name(),
|
.to_module_name(),
|
||||||
ModuleName::new_static("foo.bar")
|
ModuleName::new_static("foo.bar")
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::SitePackages(SystemPath::new(
|
ModulePathRef(ModulePathRefInner::Extra(SystemPath::new("foo/bar.pyi")))
|
||||||
|
.to_module_name(),
|
||||||
|
ModuleName::new_static("foo.bar")
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
ModulePathRef(ModulePathRefInner::SitePackages(SystemPath::new(
|
||||||
"foo/bar/__init__.pyi"
|
"foo/bar/__init__.pyi"
|
||||||
)))
|
)))
|
||||||
.to_module_name(),
|
.to_module_name(),
|
||||||
|
|
@ -926,7 +972,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn module_name_3_parts() {
|
fn module_name_3_parts() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::SitePackages(SystemPath::new(
|
ModulePathRef(ModulePathRefInner::SitePackages(SystemPath::new(
|
||||||
"foo/bar/__init__.pyi"
|
"foo/bar/__init__.pyi"
|
||||||
)))
|
)))
|
||||||
.to_module_name(),
|
.to_module_name(),
|
||||||
|
|
@ -934,7 +980,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::SitePackages(SystemPath::new(
|
ModulePathRef(ModulePathRefInner::SitePackages(SystemPath::new(
|
||||||
"foo/bar/baz"
|
"foo/bar/baz"
|
||||||
)))
|
)))
|
||||||
.to_module_name(),
|
.to_module_name(),
|
||||||
|
|
@ -945,35 +991,31 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn join() {
|
fn join() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo"))
|
ModulePathBuf::standard_library(FilePath::system("foo"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.join("bar"),
|
.join("bar"),
|
||||||
ModuleResolutionPathBuf(ModuleResolutionPathBufInner::StandardLibrary(
|
ModulePathBuf(ModulePathBufInner::StandardLibrary(FilePath::system(
|
||||||
FilePath::system("foo/bar")
|
"foo/bar"
|
||||||
))
|
)))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo"))
|
ModulePathBuf::standard_library(FilePath::system("foo"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.join("bar.pyi"),
|
.join("bar.pyi"),
|
||||||
ModuleResolutionPathBuf(ModuleResolutionPathBufInner::StandardLibrary(
|
ModulePathBuf(ModulePathBufInner::StandardLibrary(FilePath::system(
|
||||||
FilePath::system("foo/bar.pyi")
|
"foo/bar.pyi"
|
||||||
))
|
)))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::extra("foo")
|
ModulePathBuf::extra("foo").unwrap().join("bar.py"),
|
||||||
.unwrap()
|
ModulePathBuf(ModulePathBufInner::Extra(SystemPathBuf::from("foo/bar.py")))
|
||||||
.join("bar.py"),
|
|
||||||
ModuleResolutionPathBuf(ModuleResolutionPathBufInner::Extra(SystemPathBuf::from(
|
|
||||||
"foo/bar.py"
|
|
||||||
)))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Extension must be `pyi`; got `py`")]
|
#[should_panic(expected = "Extension must be `pyi`; got `py`")]
|
||||||
fn stdlib_path_invalid_join_py() {
|
fn stdlib_path_invalid_join_py() {
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo"))
|
ModulePathBuf::standard_library(FilePath::system("foo"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push("bar.py");
|
.push("bar.py");
|
||||||
}
|
}
|
||||||
|
|
@ -981,7 +1023,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Extension must be `pyi`; got `rs`")]
|
#[should_panic(expected = "Extension must be `pyi`; got `rs`")]
|
||||||
fn stdlib_path_invalid_join_rs() {
|
fn stdlib_path_invalid_join_rs() {
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo"))
|
ModulePathBuf::standard_library(FilePath::system("foo"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push("bar.rs");
|
.push("bar.rs");
|
||||||
}
|
}
|
||||||
|
|
@ -989,23 +1031,20 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Extension must be `py` or `pyi`; got `rs`")]
|
#[should_panic(expected = "Extension must be `py` or `pyi`; got `rs`")]
|
||||||
fn non_stdlib_path_invalid_join_rs() {
|
fn non_stdlib_path_invalid_join_rs() {
|
||||||
ModuleResolutionPathBuf::site_packages("foo")
|
ModulePathBuf::site_packages("foo").unwrap().push("bar.rs");
|
||||||
.unwrap()
|
|
||||||
.push("bar.rs");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "already has an extension")]
|
#[should_panic(expected = "already has an extension")]
|
||||||
fn invalid_stdlib_join_too_many_extensions() {
|
fn invalid_stdlib_join_too_many_extensions() {
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo.pyi"))
|
ModulePathBuf::standard_library(FilePath::system("foo.pyi"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push("bar.pyi");
|
.push("bar.pyi");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn relativize_stdlib_path_errors() {
|
fn relativize_stdlib_path_errors() {
|
||||||
let root =
|
let root = ModulePathBuf::standard_library(FilePath::system("foo/stdlib")).unwrap();
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo/stdlib")).unwrap();
|
|
||||||
|
|
||||||
// Must have a `.pyi` extension or no extension:
|
// Must have a `.pyi` extension or no extension:
|
||||||
let bad_absolute_path = FilePath::system("foo/stdlib/x.py");
|
let bad_absolute_path = FilePath::system("foo/stdlib/x.py");
|
||||||
|
|
@ -1020,7 +1059,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn relativize_non_stdlib_path_errors() {
|
fn relativize_non_stdlib_path_errors() {
|
||||||
let root = ModuleResolutionPathBuf::extra("foo/stdlib").unwrap();
|
let root = ModulePathBuf::extra("foo/stdlib").unwrap();
|
||||||
// Must have a `.py` extension, a `.pyi` extension, or no extension:
|
// Must have a `.py` extension, a `.pyi` extension, or no extension:
|
||||||
let bad_absolute_path = FilePath::system("foo/stdlib/x.rs");
|
let bad_absolute_path = FilePath::system("foo/stdlib/x.rs");
|
||||||
assert_eq!(root.relativize_path(&bad_absolute_path), None);
|
assert_eq!(root.relativize_path(&bad_absolute_path), None);
|
||||||
|
|
@ -1032,33 +1071,33 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn relativize_path() {
|
fn relativize_path() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModuleResolutionPathBuf::standard_library(FilePath::system("foo/baz"))
|
ModulePathBuf::standard_library(FilePath::system("foo/baz"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.relativize_path(&FilePath::system("foo/baz/eggs/__init__.pyi"))
|
.relativize_path(&FilePath::system("foo/baz/eggs/__init__.pyi"))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
ModuleResolutionPathRef(ModuleResolutionPathRefInner::StandardLibrary(
|
ModulePathRef(ModulePathRefInner::StandardLibrary(FilePathRef::system(
|
||||||
FilePathRef::system("eggs/__init__.pyi")
|
"eggs/__init__.pyi"
|
||||||
))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typeshed_test_case(
|
fn typeshed_test_case(
|
||||||
typeshed: MockedTypeshed,
|
typeshed: MockedTypeshed,
|
||||||
target_version: TargetVersion,
|
target_version: TargetVersion,
|
||||||
) -> (TestDb, ModuleResolutionPathBuf) {
|
) -> (TestDb, ModulePathBuf) {
|
||||||
let TestCase { db, stdlib, .. } = TestCaseBuilder::new()
|
let TestCase { db, stdlib, .. } = TestCaseBuilder::new()
|
||||||
.with_custom_typeshed(typeshed)
|
.with_custom_typeshed(typeshed)
|
||||||
.with_target_version(target_version)
|
.with_target_version(target_version)
|
||||||
.build();
|
.build();
|
||||||
let stdlib = ModuleResolutionPathBuf::standard_library(FilePath::System(stdlib)).unwrap();
|
let stdlib = ModulePathBuf::standard_library(FilePath::System(stdlib)).unwrap();
|
||||||
(db, stdlib)
|
(db, stdlib)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn py38_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModuleResolutionPathBuf) {
|
fn py38_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModulePathBuf) {
|
||||||
typeshed_test_case(typeshed, TargetVersion::Py38)
|
typeshed_test_case(typeshed, TargetVersion::Py38)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn py39_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModuleResolutionPathBuf) {
|
fn py39_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModulePathBuf) {
|
||||||
typeshed_test_case(typeshed, TargetVersion::Py39)
|
typeshed_test_case(typeshed, TargetVersion::Py39)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||||
|
|
@ -12,11 +11,9 @@ use ruff_db::system::{DirectoryEntry, System, SystemPath, SystemPathBuf};
|
||||||
use crate::db::Db;
|
use crate::db::Db;
|
||||||
use crate::module::{Module, ModuleKind};
|
use crate::module::{Module, ModuleKind};
|
||||||
use crate::module_name::ModuleName;
|
use crate::module_name::ModuleName;
|
||||||
use crate::path::ModuleResolutionPathBuf;
|
use crate::path::{ModulePathBuf, ModuleSearchPath};
|
||||||
use crate::state::ResolverState;
|
use crate::state::ResolverState;
|
||||||
|
|
||||||
type SearchPathRoot = Arc<ModuleResolutionPathBuf>;
|
|
||||||
|
|
||||||
/// Resolves a module name to a module.
|
/// Resolves a module name to a module.
|
||||||
pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option<Module> {
|
pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option<Module> {
|
||||||
let interned_name = internal::ModuleNameIngredient::new(db, module_name);
|
let interned_name = internal::ModuleNameIngredient::new(db, module_name);
|
||||||
|
|
@ -137,38 +134,25 @@ pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSetting
|
||||||
|
|
||||||
let mut static_search_paths: Vec<_> = extra_paths
|
let mut static_search_paths: Vec<_> = extra_paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|fs_path| {
|
.map(|path| ModuleSearchPath::extra(SystemPath::absolute(path, current_directory)).unwrap())
|
||||||
Arc::new(
|
|
||||||
ModuleResolutionPathBuf::extra(SystemPath::absolute(fs_path, current_directory))
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
static_search_paths.push(Arc::new(
|
static_search_paths.push(
|
||||||
ModuleResolutionPathBuf::first_party(SystemPath::absolute(
|
ModuleSearchPath::first_party(SystemPath::absolute(workspace_root, current_directory))
|
||||||
workspace_root,
|
.unwrap(),
|
||||||
current_directory,
|
);
|
||||||
))
|
|
||||||
.unwrap(),
|
static_search_paths.push(custom_typeshed.as_ref().map_or_else(
|
||||||
|
ModuleSearchPath::vendored_stdlib,
|
||||||
|
|custom| {
|
||||||
|
ModuleSearchPath::custom_stdlib(&SystemPath::absolute(custom, current_directory))
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
static_search_paths.push(Arc::new(custom_typeshed.as_ref().map_or_else(
|
|
||||||
ModuleResolutionPathBuf::vendored_stdlib,
|
|
||||||
|custom| {
|
|
||||||
ModuleResolutionPathBuf::stdlib_from_custom_typeshed_root(&SystemPath::absolute(
|
|
||||||
custom,
|
|
||||||
current_directory,
|
|
||||||
))
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
|
|
||||||
if let Some(path) = site_packages {
|
if let Some(path) = site_packages {
|
||||||
let site_packages_root = Arc::new(
|
let site_packages_root =
|
||||||
ModuleResolutionPathBuf::site_packages(SystemPath::absolute(path, current_directory))
|
ModuleSearchPath::site_packages(SystemPath::absolute(path, current_directory)).unwrap();
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
static_search_paths.push(site_packages_root);
|
static_search_paths.push(site_packages_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,7 +188,7 @@ pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSetting
|
||||||
/// search paths listed in `.pth` files in the `site-packages` directory
|
/// search paths listed in `.pth` files in the `site-packages` directory
|
||||||
/// due to editable installations of third-party packages.
|
/// due to editable installations of third-party packages.
|
||||||
#[salsa::tracked(return_ref)]
|
#[salsa::tracked(return_ref)]
|
||||||
pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec<Arc<ModuleResolutionPathBuf>> {
|
pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec<ModuleSearchPath> {
|
||||||
// This query needs to be re-executed each time a `.pth` file
|
// This query needs to be re-executed each time a `.pth` file
|
||||||
// is added, modified or removed from the `site-packages` directory.
|
// is added, modified or removed from the `site-packages` directory.
|
||||||
// However, we don't use Salsa queries to read the source text of `.pth` files;
|
// However, we don't use Salsa queries to read the source text of `.pth` files;
|
||||||
|
|
@ -259,7 +243,7 @@ pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec<Arc<ModuleRe
|
||||||
if existing_paths.insert(Cow::Owned(
|
if existing_paths.insert(Cow::Owned(
|
||||||
installation.as_system_path().unwrap().to_path_buf(),
|
installation.as_system_path().unwrap().to_path_buf(),
|
||||||
)) {
|
)) {
|
||||||
dynamic_paths.push(Arc::new(installation));
|
dynamic_paths.push(installation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -277,12 +261,12 @@ pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec<Arc<ModuleRe
|
||||||
/// [`sys.path` at runtime]: https://docs.python.org/3/library/site.html#module-site
|
/// [`sys.path` at runtime]: https://docs.python.org/3/library/site.html#module-site
|
||||||
struct SearchPathIterator<'db> {
|
struct SearchPathIterator<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
static_paths: std::slice::Iter<'db, SearchPathRoot>,
|
static_paths: std::slice::Iter<'db, ModuleSearchPath>,
|
||||||
dynamic_paths: Option<std::slice::Iter<'db, SearchPathRoot>>,
|
dynamic_paths: Option<std::slice::Iter<'db, ModuleSearchPath>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Iterator for SearchPathIterator<'db> {
|
impl<'db> Iterator for SearchPathIterator<'db> {
|
||||||
type Item = &'db SearchPathRoot;
|
type Item = &'db ModuleSearchPath;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let SearchPathIterator {
|
let SearchPathIterator {
|
||||||
|
|
@ -314,7 +298,7 @@ struct PthFile<'db> {
|
||||||
impl<'db> PthFile<'db> {
|
impl<'db> PthFile<'db> {
|
||||||
/// Yield paths in this `.pth` file that appear to represent editable installations,
|
/// Yield paths in this `.pth` file that appear to represent editable installations,
|
||||||
/// and should therefore be added as module-resolution search paths.
|
/// and should therefore be added as module-resolution search paths.
|
||||||
fn editable_installations(&'db self) -> impl Iterator<Item = ModuleResolutionPathBuf> + 'db {
|
fn editable_installations(&'db self) -> impl Iterator<Item = ModuleSearchPath> + 'db {
|
||||||
let PthFile {
|
let PthFile {
|
||||||
system,
|
system,
|
||||||
path: _,
|
path: _,
|
||||||
|
|
@ -336,7 +320,7 @@ impl<'db> PthFile<'db> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let possible_editable_install = SystemPath::absolute(line, site_packages);
|
let possible_editable_install = SystemPath::absolute(line, site_packages);
|
||||||
ModuleResolutionPathBuf::editable_installation_root(*system, possible_editable_install)
|
ModuleSearchPath::editable(*system, possible_editable_install)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -408,7 +392,7 @@ pub(crate) struct ModuleResolutionSettings {
|
||||||
///
|
///
|
||||||
/// Note that `site-packages` *is included* as a search path in this sequence,
|
/// Note that `site-packages` *is included* as a search path in this sequence,
|
||||||
/// but it is also stored separately so that we're able to find editable installs later.
|
/// but it is also stored separately so that we're able to find editable installs later.
|
||||||
static_search_paths: Vec<SearchPathRoot>,
|
static_search_paths: Vec<ModuleSearchPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleResolutionSettings {
|
impl ModuleResolutionSettings {
|
||||||
|
|
@ -491,10 +475,7 @@ static BUILTIN_MODULES: Lazy<FxHashSet<&str>> = Lazy::new(|| {
|
||||||
|
|
||||||
/// Given a module name and a list of search paths in which to lookup modules,
|
/// Given a module name and a list of search paths in which to lookup modules,
|
||||||
/// attempt to resolve the module name
|
/// attempt to resolve the module name
|
||||||
fn resolve_name(
|
fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(ModuleSearchPath, File, ModuleKind)> {
|
||||||
db: &dyn Db,
|
|
||||||
name: &ModuleName,
|
|
||||||
) -> Option<(Arc<ModuleResolutionPathBuf>, File, ModuleKind)> {
|
|
||||||
let resolver_settings = module_resolution_settings(db);
|
let resolver_settings = module_resolution_settings(db);
|
||||||
let resolver_state = ResolverState::new(db, resolver_settings.target_version());
|
let resolver_state = ResolverState::new(db, resolver_settings.target_version());
|
||||||
let is_builtin_module = BUILTIN_MODULES.contains(&name.as_str());
|
let is_builtin_module = BUILTIN_MODULES.contains(&name.as_str());
|
||||||
|
|
@ -554,14 +535,14 @@ fn resolve_name(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_package<'a, 'db, I>(
|
fn resolve_package<'a, 'db, I>(
|
||||||
module_search_path: &ModuleResolutionPathBuf,
|
module_search_path: &ModuleSearchPath,
|
||||||
components: I,
|
components: I,
|
||||||
resolver_state: &ResolverState<'db>,
|
resolver_state: &ResolverState<'db>,
|
||||||
) -> Result<ResolvedPackage, PackageKind>
|
) -> Result<ResolvedPackage, PackageKind>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a str>,
|
I: Iterator<Item = &'a str>,
|
||||||
{
|
{
|
||||||
let mut package_path = module_search_path.clone();
|
let mut package_path = module_search_path.as_module_path().clone();
|
||||||
|
|
||||||
// `true` if inside a folder that is a namespace package (has no `__init__.py`).
|
// `true` if inside a folder that is a namespace package (has no `__init__.py`).
|
||||||
// Namespace packages are special because they can be spread across multiple search paths.
|
// Namespace packages are special because they can be spread across multiple search paths.
|
||||||
|
|
@ -613,7 +594,7 @@ where
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ResolvedPackage {
|
struct ResolvedPackage {
|
||||||
path: ModuleResolutionPathBuf,
|
path: ModulePathBuf,
|
||||||
kind: PackageKind,
|
kind: PackageKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -669,7 +650,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!("foo", foo_module.name());
|
assert_eq!("foo", foo_module.name());
|
||||||
assert_eq!(&src, &foo_module.search_path());
|
assert_eq!(&src, foo_module.search_path());
|
||||||
assert_eq!(ModuleKind::Module, foo_module.kind());
|
assert_eq!(ModuleKind::Module, foo_module.kind());
|
||||||
|
|
||||||
let expected_foo_path = src.join("foo.py");
|
let expected_foo_path = src.join("foo.py");
|
||||||
|
|
@ -734,7 +715,7 @@ mod tests {
|
||||||
resolve_module(&db, functools_module_name).as_ref()
|
resolve_module(&db, functools_module_name).as_ref()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(&stdlib, &functools_module.search_path().to_path_buf());
|
assert_eq!(&stdlib, functools_module.search_path());
|
||||||
assert_eq!(ModuleKind::Module, functools_module.kind());
|
assert_eq!(ModuleKind::Module, functools_module.kind());
|
||||||
|
|
||||||
let expected_functools_path = stdlib.join("functools.pyi");
|
let expected_functools_path = stdlib.join("functools.pyi");
|
||||||
|
|
@ -786,7 +767,7 @@ mod tests {
|
||||||
});
|
});
|
||||||
let search_path = resolved_module.search_path();
|
let search_path = resolved_module.search_path();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&stdlib, &search_path,
|
&stdlib, search_path,
|
||||||
"Search path for {module_name} was unexpectedly {search_path:?}"
|
"Search path for {module_name} was unexpectedly {search_path:?}"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -882,7 +863,7 @@ mod tests {
|
||||||
});
|
});
|
||||||
let search_path = resolved_module.search_path();
|
let search_path = resolved_module.search_path();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&stdlib, &search_path,
|
&stdlib, search_path,
|
||||||
"Search path for {module_name} was unexpectedly {search_path:?}"
|
"Search path for {module_name} was unexpectedly {search_path:?}"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -941,7 +922,7 @@ mod tests {
|
||||||
Some(&functools_module),
|
Some(&functools_module),
|
||||||
resolve_module(&db, functools_module_name).as_ref()
|
resolve_module(&db, functools_module_name).as_ref()
|
||||||
);
|
);
|
||||||
assert_eq!(&src, &functools_module.search_path());
|
assert_eq!(&src, functools_module.search_path());
|
||||||
assert_eq!(ModuleKind::Module, functools_module.kind());
|
assert_eq!(ModuleKind::Module, functools_module.kind());
|
||||||
assert_eq!(&src.join("functools.py"), functools_module.file().path(&db));
|
assert_eq!(&src.join("functools.py"), functools_module.file().path(&db));
|
||||||
|
|
||||||
|
|
@ -962,7 +943,7 @@ mod tests {
|
||||||
let pydoc_data_topics = resolve_module(&db, pydoc_data_topics_name).unwrap();
|
let pydoc_data_topics = resolve_module(&db, pydoc_data_topics_name).unwrap();
|
||||||
|
|
||||||
assert_eq!("pydoc_data.topics", pydoc_data_topics.name());
|
assert_eq!("pydoc_data.topics", pydoc_data_topics.name());
|
||||||
assert_eq!(pydoc_data_topics.search_path(), stdlib);
|
assert_eq!(pydoc_data_topics.search_path(), &stdlib);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pydoc_data_topics.file().path(&db),
|
pydoc_data_topics.file().path(&db),
|
||||||
&stdlib.join("pydoc_data/topics.pyi")
|
&stdlib.join("pydoc_data/topics.pyi")
|
||||||
|
|
@ -979,7 +960,7 @@ mod tests {
|
||||||
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
|
|
||||||
assert_eq!("foo", foo_module.name());
|
assert_eq!("foo", foo_module.name());
|
||||||
assert_eq!(&src, &foo_module.search_path());
|
assert_eq!(&src, foo_module.search_path());
|
||||||
assert_eq!(&foo_path, foo_module.file().path(&db));
|
assert_eq!(&foo_path, foo_module.file().path(&db));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -1006,7 +987,7 @@ mod tests {
|
||||||
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
let foo_init_path = src.join("foo/__init__.py");
|
let foo_init_path = src.join("foo/__init__.py");
|
||||||
|
|
||||||
assert_eq!(&src, &foo_module.search_path());
|
assert_eq!(&src, foo_module.search_path());
|
||||||
assert_eq!(&foo_init_path, foo_module.file().path(&db));
|
assert_eq!(&foo_init_path, foo_module.file().path(&db));
|
||||||
assert_eq!(ModuleKind::Package, foo_module.kind());
|
assert_eq!(ModuleKind::Package, foo_module.kind());
|
||||||
|
|
||||||
|
|
@ -1029,7 +1010,6 @@ mod tests {
|
||||||
let foo = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
let foo_stub = src.join("foo.pyi");
|
let foo_stub = src.join("foo.pyi");
|
||||||
|
|
||||||
assert_eq!(&src, &foo.search_path());
|
|
||||||
assert_eq!(&foo_stub, foo.file().path(&db));
|
assert_eq!(&foo_stub, foo.file().path(&db));
|
||||||
|
|
||||||
assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub)));
|
assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub)));
|
||||||
|
|
@ -1053,7 +1033,7 @@ mod tests {
|
||||||
resolve_module(&db, ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
|
resolve_module(&db, ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
|
||||||
let baz_path = src.join("foo/bar/baz.py");
|
let baz_path = src.join("foo/bar/baz.py");
|
||||||
|
|
||||||
assert_eq!(&src, &baz_module.search_path());
|
assert_eq!(&src, baz_module.search_path());
|
||||||
assert_eq!(&baz_path, baz_module.file().path(&db));
|
assert_eq!(&baz_path, baz_module.file().path(&db));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -1153,7 +1133,7 @@ mod tests {
|
||||||
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
let foo_src_path = src.join("foo.py");
|
let foo_src_path = src.join("foo.py");
|
||||||
|
|
||||||
assert_eq!(&src, &foo_module.search_path());
|
assert_eq!(&src, foo_module.search_path());
|
||||||
assert_eq!(&foo_src_path, foo_module.file().path(&db));
|
assert_eq!(&foo_src_path, foo_module.file().path(&db));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(foo_module),
|
Some(foo_module),
|
||||||
|
|
@ -1205,12 +1185,12 @@ mod tests {
|
||||||
|
|
||||||
assert_ne!(foo_module, bar_module);
|
assert_ne!(foo_module, bar_module);
|
||||||
|
|
||||||
assert_eq!(&src, &foo_module.search_path());
|
assert_eq!(&src, foo_module.search_path());
|
||||||
assert_eq!(&foo, foo_module.file().path(&db));
|
assert_eq!(&foo, foo_module.file().path(&db));
|
||||||
|
|
||||||
// `foo` and `bar` shouldn't resolve to the same file
|
// `foo` and `bar` shouldn't resolve to the same file
|
||||||
|
|
||||||
assert_eq!(&src, &bar_module.search_path());
|
assert_eq!(&src, bar_module.search_path());
|
||||||
assert_eq!(&bar, bar_module.file().path(&db));
|
assert_eq!(&bar, bar_module.file().path(&db));
|
||||||
assert_eq!(&foo, foo_module.file().path(&db));
|
assert_eq!(&foo, foo_module.file().path(&db));
|
||||||
|
|
||||||
|
|
@ -1326,7 +1306,7 @@ mod tests {
|
||||||
let stdlib_functools_path = stdlib.join("functools.pyi");
|
let stdlib_functools_path = stdlib.join("functools.pyi");
|
||||||
|
|
||||||
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
||||||
assert_eq!(functools_module.search_path(), stdlib);
|
assert_eq!(functools_module.search_path(), &stdlib);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(functools_module.file()),
|
Some(functools_module.file()),
|
||||||
system_path_to_file(&db, &stdlib_functools_path)
|
system_path_to_file(&db, &stdlib_functools_path)
|
||||||
|
|
@ -1346,7 +1326,7 @@ mod tests {
|
||||||
&ModuleNameIngredient::new(&db, functools_module_name.clone()),
|
&ModuleNameIngredient::new(&db, functools_module_name.clone()),
|
||||||
&events,
|
&events,
|
||||||
);
|
);
|
||||||
assert_eq!(functools_module.search_path(), stdlib);
|
assert_eq!(functools_module.search_path(), &stdlib);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(functools_module.file()),
|
Some(functools_module.file()),
|
||||||
system_path_to_file(&db, &stdlib_functools_path)
|
system_path_to_file(&db, &stdlib_functools_path)
|
||||||
|
|
@ -1372,7 +1352,7 @@ mod tests {
|
||||||
|
|
||||||
let functools_module_name = ModuleName::new_static("functools").unwrap();
|
let functools_module_name = ModuleName::new_static("functools").unwrap();
|
||||||
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
||||||
assert_eq!(functools_module.search_path(), stdlib);
|
assert_eq!(functools_module.search_path(), &stdlib);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(functools_module.file()),
|
Some(functools_module.file()),
|
||||||
system_path_to_file(&db, stdlib.join("functools.pyi"))
|
system_path_to_file(&db, stdlib.join("functools.pyi"))
|
||||||
|
|
@ -1383,7 +1363,7 @@ mod tests {
|
||||||
let src_functools_path = src.join("functools.py");
|
let src_functools_path = src.join("functools.py");
|
||||||
db.write_file(&src_functools_path, "FOO: int").unwrap();
|
db.write_file(&src_functools_path, "FOO: int").unwrap();
|
||||||
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
||||||
assert_eq!(functools_module.search_path(), src);
|
assert_eq!(functools_module.search_path(), &src);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(functools_module.file()),
|
Some(functools_module.file()),
|
||||||
system_path_to_file(&db, &src_functools_path)
|
system_path_to_file(&db, &src_functools_path)
|
||||||
|
|
@ -1414,7 +1394,7 @@ mod tests {
|
||||||
let src_functools_path = src.join("functools.py");
|
let src_functools_path = src.join("functools.py");
|
||||||
|
|
||||||
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
||||||
assert_eq!(functools_module.search_path(), src);
|
assert_eq!(functools_module.search_path(), &src);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(functools_module.file()),
|
Some(functools_module.file()),
|
||||||
system_path_to_file(&db, &src_functools_path)
|
system_path_to_file(&db, &src_functools_path)
|
||||||
|
|
@ -1427,7 +1407,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
File::touch_path(&mut db, &src_functools_path);
|
File::touch_path(&mut db, &src_functools_path);
|
||||||
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
|
||||||
assert_eq!(functools_module.search_path(), stdlib);
|
assert_eq!(functools_module.search_path(), &stdlib);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(functools_module.file()),
|
Some(functools_module.file()),
|
||||||
system_path_to_file(&db, stdlib.join("functools.pyi"))
|
system_path_to_file(&db, stdlib.join("functools.pyi"))
|
||||||
|
|
@ -1677,15 +1657,14 @@ not_a_directory
|
||||||
.with_site_packages_files(&[("_foo.pth", "/src")])
|
.with_site_packages_files(&[("_foo.pth", "/src")])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let search_paths: Vec<&SearchPathRoot> =
|
let search_paths: Vec<&ModuleSearchPath> =
|
||||||
module_resolution_settings(&db).search_paths(&db).collect();
|
module_resolution_settings(&db).search_paths(&db).collect();
|
||||||
|
|
||||||
assert!(search_paths.contains(&&Arc::new(
|
assert!(search_paths
|
||||||
ModuleResolutionPathBuf::first_party("/src").unwrap()
|
.contains(&&ModuleSearchPath::first_party(SystemPathBuf::from("/src")).unwrap()));
|
||||||
)));
|
|
||||||
|
|
||||||
assert!(!search_paths.contains(&&Arc::new(
|
assert!(!search_paths.contains(
|
||||||
ModuleResolutionPathBuf::editable_installation_root(db.system(), "/src").unwrap()
|
&&ModuleSearchPath::editable(db.system(), SystemPathBuf::from("/src")).unwrap()
|
||||||
)));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,8 @@ pub struct SearchPathSettings {
|
||||||
/// The root of the workspace, used for finding first-party modules.
|
/// The root of the workspace, used for finding first-party modules.
|
||||||
pub workspace_root: SystemPathBuf,
|
pub workspace_root: SystemPathBuf,
|
||||||
|
|
||||||
/// Optional (already validated) path to standard-library typeshed stubs.
|
/// Optional path to a "custom typeshed" directory on disk for us to use for standard-library types.
|
||||||
/// If this is not provided, we will fallback to our vendored typeshed stubs
|
/// If this is not provided, we will fallback to our vendored typeshed stubs for the stdlib,
|
||||||
/// bundled as a zip file in the binary
|
/// bundled as a zip file in the binary
|
||||||
pub custom_typeshed: Option<SystemPathBuf>,
|
pub custom_typeshed: Option<SystemPathBuf>,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue