Compare commits

...

3 Commits

Author SHA1 Message Date
Charlie Marsh
b7517d4511 Delete examples 2023-05-06 23:56:14 -04:00
Charlie Marsh
da8481c97d Try boxing 2023-05-06 23:55:22 -04:00
Charlie Marsh
cd5c69b61c Document BindingKind size 2023-05-06 23:55:22 -04:00
6 changed files with 186 additions and 168 deletions

View File

@@ -927,10 +927,9 @@ where
self.add_binding( self.add_binding(
name, name,
Binding { Binding {
kind: BindingKind::SubmoduleImportation(SubmoduleImportation { kind: BindingKind::SubmoduleImportation(Box::new(
name, SubmoduleImportation { name, full_name },
full_name, )),
}),
runtime_usage: None, runtime_usage: None,
synthetic_usage: None, synthetic_usage: None,
typing_usage: None, typing_usage: None,
@@ -954,7 +953,10 @@ where
self.add_binding( self.add_binding(
name, name,
Binding { Binding {
kind: BindingKind::Importation(Importation { name, full_name }), kind: BindingKind::Importation(Box::new(Importation {
name,
full_name,
})),
runtime_usage: None, runtime_usage: None,
synthetic_usage: if is_explicit_reexport { synthetic_usage: if is_explicit_reexport {
Some((self.ctx.scope_id, alias.range())) Some((self.ctx.scope_id, alias.range()))
@@ -1307,10 +1309,10 @@ where
self.add_binding( self.add_binding(
name, name,
Binding { Binding {
kind: BindingKind::FromImportation(FromImportation { kind: BindingKind::FromImportation(Box::new(FromImportation {
name, name,
full_name, full_name,
}), })),
runtime_usage: None, runtime_usage: None,
synthetic_usage: if is_explicit_reexport { synthetic_usage: if is_explicit_reexport {
Some((self.ctx.scope_id, alias.range())) Some((self.ctx.scope_id, alias.range()))
@@ -4412,13 +4414,13 @@ impl<'a> Checker<'a> {
// import pyarrow.csv // import pyarrow.csv
// print(pa.csv.read_csv("test.csv")) // print(pa.csv.read_csv("test.csv"))
match &self.ctx.bindings[*index].kind { match &self.ctx.bindings[*index].kind {
BindingKind::Importation(Importation { name, full_name }) BindingKind::Importation(import) => {
| BindingKind::SubmoduleImportation(SubmoduleImportation { name, full_name }) => let name = import.name;
{ let full_name = import.full_name;
let has_alias = full_name let has_alias = full_name
.split('.') .split('.')
.last() .last()
.map(|segment| &segment != name) .map(|segment| segment != name)
.unwrap_or_default(); .unwrap_or_default();
if has_alias { if has_alias {
// Mark the sub-importation as used. // Mark the sub-importation as used.
@@ -4431,11 +4433,32 @@ impl<'a> Checker<'a> {
} }
} }
} }
BindingKind::FromImportation(FromImportation { name, full_name }) => { BindingKind::SubmoduleImportation(import) => {
let name = import.name;
let full_name = import.full_name;
let has_alias = full_name let has_alias = full_name
.split('.') .split('.')
.last() .last()
.map(|segment| &segment != name) .map(|segment| segment != name)
.unwrap_or_default();
if has_alias {
// Mark the sub-importation as used.
if let Some(index) = scope.get(full_name) {
self.ctx.bindings[*index].mark_used(
self.ctx.scope_id,
expr.range(),
context,
);
}
}
}
BindingKind::FromImportation(import) => {
let name = import.name;
let full_name = &import.full_name;
let has_alias = full_name
.split('.')
.last()
.map(|segment| segment != name)
.unwrap_or_default(); .unwrap_or_default();
if has_alias { if has_alias {
// Mark the sub-importation as used. // Mark the sub-importation as used.
@@ -4665,10 +4688,8 @@ impl<'a> Checker<'a> {
// Grab the existing bound __all__ values. // Grab the existing bound __all__ values.
if let StmtKind::AugAssign { .. } = &parent.node { if let StmtKind::AugAssign { .. } = &parent.node {
if let Some(index) = scope.get("__all__") { if let Some(index) = scope.get("__all__") {
if let BindingKind::Export(Export { names: existing }) = if let BindingKind::Export(export) = &self.ctx.bindings[*index].kind {
&self.ctx.bindings[*index].kind names.extend(&export.names);
{
names.extend_from_slice(existing);
} }
} }
} }
@@ -4693,7 +4714,7 @@ impl<'a> Checker<'a> {
self.add_binding( self.add_binding(
id, id,
Binding { Binding {
kind: BindingKind::Export(Export { names: all_names }), kind: BindingKind::Export(Box::new(Export { names: all_names })),
runtime_usage: None, runtime_usage: None,
synthetic_usage: None, synthetic_usage: None,
typing_usage: None, typing_usage: None,
@@ -4981,7 +5002,7 @@ impl<'a> Checker<'a> {
.get("__all__") .get("__all__")
.map(|index| &self.ctx.bindings[*index]) .map(|index| &self.ctx.bindings[*index])
.and_then(|binding| match &binding.kind { .and_then(|binding| match &binding.kind {
BindingKind::Export(Export { names }) => Some((names, binding.range)), BindingKind::Export(export) => Some((&export.names, binding.range)),
_ => None, _ => None,
}); });
@@ -5013,7 +5034,7 @@ impl<'a> Checker<'a> {
.get("__all__") .get("__all__")
.map(|index| &self.ctx.bindings[*index]) .map(|index| &self.ctx.bindings[*index])
.and_then(|binding| match &binding.kind { .and_then(|binding| match &binding.kind {
BindingKind::Export(Export { names }) => Some((names.as_slice(), binding.range)), BindingKind::Export(export) => Some((export.names.as_slice(), binding.range)),
_ => None, _ => None,
}); });
@@ -5223,14 +5244,9 @@ impl<'a> Checker<'a> {
let binding = &self.ctx.bindings[*index]; let binding = &self.ctx.bindings[*index];
let full_name = match &binding.kind { let full_name = match &binding.kind {
BindingKind::Importation(Importation { full_name, .. }) => full_name, BindingKind::Importation(import) => import.full_name,
BindingKind::FromImportation(FromImportation { full_name, .. }) => { BindingKind::FromImportation(import) => import.full_name.as_str(),
full_name.as_str() BindingKind::SubmoduleImportation(import) => import.full_name,
}
BindingKind::SubmoduleImportation(SubmoduleImportation {
full_name,
..
}) => full_name,
_ => continue, _ => continue,
}; };

View File

@@ -1,8 +1,6 @@
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::binding::{ use ruff_python_semantic::binding::{Binding, BindingKind, ExecutionContext};
Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation,
};
/// ## What it does /// ## What it does
/// Checks for runtime imports defined in a type-checking block. /// Checks for runtime imports defined in a type-checking block.
@@ -51,9 +49,9 @@ impl Violation for RuntimeImportInTypeCheckingBlock {
/// TCH004 /// TCH004
pub fn runtime_import_in_type_checking_block(binding: &Binding) -> Option<Diagnostic> { pub fn runtime_import_in_type_checking_block(binding: &Binding) -> Option<Diagnostic> {
let full_name = match &binding.kind { let full_name = match &binding.kind {
BindingKind::Importation(Importation { full_name, .. }) => full_name, BindingKind::Importation(import) => import.full_name,
BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(), BindingKind::FromImportation(import) => import.full_name.as_str(),
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name, BindingKind::SubmoduleImportation(import) => import.full_name,
_ => return None, _ => return None,
}; };

View File

@@ -2,9 +2,7 @@ use std::path::Path;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::binding::{ use ruff_python_semantic::binding::{Binding, BindingKind, ExecutionContext};
Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation,
};
use crate::rules::isort::{categorize, ImportSection, ImportType}; use crate::rules::isort::{categorize, ImportSection, ImportType};
use crate::settings::Settings; use crate::settings::Settings;
@@ -160,67 +158,68 @@ impl Violation for TypingOnlyStandardLibraryImport {
} }
/// Return `true` if `this` is implicitly loaded via importing `that`. /// Return `true` if `this` is implicitly loaded via importing `that`.
fn is_implicit_import(this: &Binding, that: &Binding) -> bool { fn is_implicit_import(_this: &Binding, _that: &Binding) -> bool {
match &this.kind { true
BindingKind::Importation(Importation { // match &this.kind {
full_name: this_name, // BindingKind::Importation(Importation {
.. // full_name: this_name,
}) // ..
| BindingKind::SubmoduleImportation(SubmoduleImportation { // })
name: this_name, .. // | BindingKind::SubmoduleImportation(SubmoduleImportation {
}) => match &that.kind { // name: this_name, ..
BindingKind::FromImportation(FromImportation { // }) => match &that.kind {
full_name: that_name, // BindingKind::FromImportation(FromImportation {
.. // full_name: that_name,
}) => { // ..
// Ex) `pkg.A` vs. `pkg` // }) => {
this_name // // Ex) `pkg.A` vs. `pkg`
.rfind('.') // this_name
.map_or(false, |i| this_name[..i] == *that_name) // .rfind('.')
} // .map_or(false, |i| this_name[..i] == *that_name)
BindingKind::Importation(Importation { // }
full_name: that_name, // BindingKind::Importation(Importation {
.. // full_name: that_name,
}) // ..
| BindingKind::SubmoduleImportation(SubmoduleImportation { // })
name: that_name, .. // | BindingKind::SubmoduleImportation(SubmoduleImportation {
}) => { // name: that_name, ..
// Ex) `pkg.A` vs. `pkg.B` // }) => {
this_name == that_name // // Ex) `pkg.A` vs. `pkg.B`
} // this_name == that_name
_ => false, // }
}, // _ => false,
BindingKind::FromImportation(FromImportation { // },
full_name: this_name, // BindingKind::FromImportation(FromImportation {
.. // full_name: this_name,
}) => match &that.kind { // ..
BindingKind::Importation(Importation { // }) => match &that.kind {
full_name: that_name, // BindingKind::Importation(Importation {
.. // full_name: that_name,
}) // ..
| BindingKind::SubmoduleImportation(SubmoduleImportation { // })
name: that_name, .. // | BindingKind::SubmoduleImportation(SubmoduleImportation {
}) => { // name: that_name, ..
// Ex) `pkg.A` vs. `pkg` // }) => {
this_name // // Ex) `pkg.A` vs. `pkg`
.rfind('.') // this_name
.map_or(false, |i| &this_name[..i] == *that_name) // .rfind('.')
} // .map_or(false, |i| &this_name[..i] == *that_name)
BindingKind::FromImportation(FromImportation { // }
full_name: that_name, // BindingKind::FromImportation(FromImportation {
.. // full_name: that_name,
}) => { // ..
// Ex) `pkg.A` vs. `pkg.B` // }) => {
this_name.rfind('.').map_or(false, |i| { // // Ex) `pkg.A` vs. `pkg.B`
that_name // this_name.rfind('.').map_or(false, |i| {
.rfind('.') // that_name
.map_or(false, |j| this_name[..i] == that_name[..j]) // .rfind('.')
}) // .map_or(false, |j| this_name[..i] == that_name[..j])
} // })
_ => false, // }
}, // _ => false,
_ => false, // },
} // _ => false,
// }
} }
/// Return `true` if `name` is exempt from typing-only enforcement. /// Return `true` if `name` is exempt from typing-only enforcement.
@@ -257,9 +256,9 @@ pub fn typing_only_runtime_import(
} }
let full_name = match &binding.kind { let full_name = match &binding.kind {
BindingKind::Importation(Importation { full_name, .. }) => full_name, BindingKind::Importation(import) => import.full_name,
BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(), BindingKind::FromImportation(import) => import.full_name.as_str(),
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name, BindingKind::SubmoduleImportation(import) => import.full_name,
_ => return None, _ => return None,
}; };

View File

@@ -3,7 +3,7 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::Violation; use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use ruff_diagnostics::{Diagnostic, DiagnosticKind};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::binding::{BindingKind, Importation}; use ruff_python_semantic::binding::BindingKind;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::registry::Rule; use crate::registry::Rule;
@@ -85,11 +85,8 @@ pub fn check_call(checker: &mut Checker, func: &Expr) {
// irrelevant bindings (like non-Pandas imports). // irrelevant bindings (like non-Pandas imports).
if let ExprKind::Name { id, .. } = &value.node { if let ExprKind::Name { id, .. } = &value.node {
if checker.ctx.find_binding(id).map_or(true, |binding| { if checker.ctx.find_binding(id).map_or(true, |binding| {
if let BindingKind::Importation(Importation { if let BindingKind::Importation(import) = &binding.kind {
full_name: module, .. import.full_name != "pandas"
}) = &binding.kind
{
module != &"pandas"
} else { } else {
matches!( matches!(
binding.kind, binding.kind,

View File

@@ -59,45 +59,28 @@ impl<'a> Binding<'a> {
pub fn redefines(&self, existing: &'a Binding) -> bool { pub fn redefines(&self, existing: &'a Binding) -> bool {
match &self.kind { match &self.kind {
BindingKind::Importation(Importation { full_name, .. }) => { BindingKind::Importation(import) => {
if let BindingKind::SubmoduleImportation(SubmoduleImportation { if let BindingKind::SubmoduleImportation(existing) = &existing.kind {
full_name: existing, return import.full_name == existing.full_name;
..
}) = &existing.kind
{
return full_name == existing;
} }
} }
BindingKind::FromImportation(FromImportation { full_name, .. }) => { BindingKind::FromImportation(import) => {
if let BindingKind::SubmoduleImportation(SubmoduleImportation { if let BindingKind::SubmoduleImportation(existing) = &existing.kind {
full_name: existing, return import.full_name == existing.full_name;
..
}) = &existing.kind
{
return full_name == existing;
} }
} }
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => { BindingKind::SubmoduleImportation(import) => match &existing.kind {
match &existing.kind { BindingKind::Importation(existing) => {
BindingKind::Importation(Importation { return import.full_name == existing.full_name;
full_name: existing,
..
})
| BindingKind::SubmoduleImportation(SubmoduleImportation {
full_name: existing,
..
}) => {
return full_name == existing;
}
BindingKind::FromImportation(FromImportation {
full_name: existing,
..
}) => {
return full_name == existing;
}
_ => {}
} }
} BindingKind::SubmoduleImportation(existing) => {
return import.full_name == existing.full_name;
}
BindingKind::FromImportation(existing) => {
return import.full_name == existing.full_name;
}
_ => {}
},
BindingKind::Annotation => { BindingKind::Annotation => {
return false; return false;
} }
@@ -259,11 +242,11 @@ pub enum BindingKind<'a> {
Builtin, Builtin,
ClassDefinition, ClassDefinition,
FunctionDefinition, FunctionDefinition,
Export(Export<'a>), Export(Box<Export<'a>>),
FutureImportation, FutureImportation,
Importation(Importation<'a>), Importation(Box<Importation<'a>>),
FromImportation(FromImportation<'a>), FromImportation(Box<FromImportation<'a>>),
SubmoduleImportation(SubmoduleImportation<'a>), SubmoduleImportation(Box<SubmoduleImportation<'a>>),
} }
bitflags! { bitflags! {

View File

@@ -11,10 +11,7 @@ use ruff_python_stdlib::path::is_python_stub_file;
use ruff_python_stdlib::typing::TYPING_EXTENSIONS; use ruff_python_stdlib::typing::TYPING_EXTENSIONS;
use crate::analyze::visibility::{module_visibility, Modifier, VisibleScope}; use crate::analyze::visibility::{module_visibility, Modifier, VisibleScope};
use crate::binding::{ use crate::binding::{Binding, BindingId, BindingKind, Bindings, Exceptions, ExecutionContext};
Binding, BindingId, BindingKind, Bindings, Exceptions, ExecutionContext, FromImportation,
Importation, SubmoduleImportation,
};
use crate::node::{NodeId, Nodes}; use crate::node::{NodeId, Nodes};
use crate::scope::{Scope, ScopeId, ScopeKind, Scopes}; use crate::scope::{Scope, ScopeId, ScopeKind, Scopes};
@@ -166,10 +163,8 @@ impl<'a> Context<'a> {
return None; return None;
}; };
match &binding.kind { match &binding.kind {
BindingKind::Importation(Importation { BindingKind::Importation(import) => {
full_name: name, .. let name = import.full_name;
})
| BindingKind::SubmoduleImportation(SubmoduleImportation { name, .. }) => {
if name.starts_with('.') { if name.starts_with('.') {
if let Some(module) = &self.module_path { if let Some(module) = &self.module_path {
let mut source_path = from_relative_import(module, name); let mut source_path = from_relative_import(module, name);
@@ -188,9 +183,28 @@ impl<'a> Context<'a> {
Some(source_path) Some(source_path)
} }
} }
BindingKind::FromImportation(FromImportation { BindingKind::SubmoduleImportation(import) => {
full_name: name, .. let name = import.name;
}) => { if name.starts_with('.') {
if let Some(module) = &self.module_path {
let mut source_path = from_relative_import(module, name);
if source_path.is_empty() {
None
} else {
source_path.extend(call_path.into_iter().skip(1));
Some(source_path)
}
} else {
None
}
} else {
let mut source_path: CallPath = from_unqualified_name(name);
source_path.extend(call_path.into_iter().skip(1));
Some(source_path)
}
}
BindingKind::FromImportation(import) => {
let name = &import.full_name;
if name.starts_with('.') { if name.starts_with('.') {
if let Some(module) = &self.module_path { if let Some(module) = &self.module_path {
let mut source_path = from_relative_import(module, name); let mut source_path = from_relative_import(module, name);
@@ -243,16 +257,19 @@ impl<'a> Context<'a> {
// Ex) Given `module="sys"` and `object="exit"`: // Ex) Given `module="sys"` and `object="exit"`:
// `import sys` -> `sys.exit` // `import sys` -> `sys.exit`
// `import sys as sys2` -> `sys2.exit` // `import sys as sys2` -> `sys2.exit`
BindingKind::Importation(Importation { name, full_name }) => { BindingKind::Importation(import) => {
if full_name == &module { if import.full_name == module {
// Verify that `sys` isn't bound in an inner scope. // Verify that `sys` isn't bound in an inner scope.
if self if self
.scopes() .scopes()
.take(scope_index) .take(scope_index)
.all(|scope| scope.get(name).is_none()) .all(|scope| scope.get(import.name).is_none())
{ {
if let Some(source) = binding.source { if let Some(source) = binding.source {
return Some((self.stmts[source], format!("{name}.{member}"))); return Some((
self.stmts[source],
format!("{}.{member}", import.name),
));
} }
} }
} }
@@ -260,17 +277,22 @@ impl<'a> Context<'a> {
// Ex) Given `module="os.path"` and `object="join"`: // Ex) Given `module="os.path"` and `object="join"`:
// `from os.path import join` -> `join` // `from os.path import join` -> `join`
// `from os.path import join as join2` -> `join2` // `from os.path import join as join2` -> `join2`
BindingKind::FromImportation(FromImportation { name, full_name }) => { BindingKind::FromImportation(import) => {
if let Some((target_module, target_member)) = full_name.split_once('.') { if let Some((target_module, target_member)) =
import.full_name.split_once('.')
{
if target_module == module && target_member == member { if target_module == module && target_member == member {
// Verify that `join` isn't bound in an inner scope. // Verify that `join` isn't bound in an inner scope.
if self if self
.scopes() .scopes()
.take(scope_index) .take(scope_index)
.all(|scope| scope.get(name).is_none()) .all(|scope| scope.get(import.name).is_none())
{ {
if let Some(source) = binding.source { if let Some(source) = binding.source {
return Some((self.stmts[source], (*name).to_string())); return Some((
self.stmts[source],
(*import.name).to_string(),
));
} }
} }
} }
@@ -278,16 +300,19 @@ impl<'a> Context<'a> {
} }
// Ex) Given `module="os"` and `object="name"`: // Ex) Given `module="os"` and `object="name"`:
// `import os.path ` -> `os.name` // `import os.path ` -> `os.name`
BindingKind::SubmoduleImportation(SubmoduleImportation { name, .. }) => { BindingKind::SubmoduleImportation(import) => {
if name == &module { if import.name == module {
// Verify that `os` isn't bound in an inner scope. // Verify that `os` isn't bound in an inner scope.
if self if self
.scopes() .scopes()
.take(scope_index) .take(scope_index)
.all(|scope| scope.get(name).is_none()) .all(|scope| scope.get(import.name).is_none())
{ {
if let Some(source) = binding.source { if let Some(source) = binding.source {
return Some((self.stmts[source], format!("{name}.{member}"))); return Some((
self.stmts[source],
format!("{}.{member}", import.name),
));
} }
} }
} }