Base INP check on package inference (#2079)

If a file doesn't have a `package`, then it must both be in a directory that lacks an `__init__.py`, and a directory that _isn't_ marked as a namespace package.

Closes #2075.
This commit is contained in:
Charlie Marsh
2023-01-21 19:49:56 -05:00
committed by GitHub
parent 28f05aa6e7
commit 84b1490d03
9 changed files with 34 additions and 16 deletions

View File

@@ -4,12 +4,16 @@ use crate::registry::{Diagnostic, Rule};
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
use crate::settings::Settings;
pub fn check_file_path(path: &Path, settings: &Settings) -> Vec<Diagnostic> {
pub fn check_file_path(
path: &Path,
package: Option<&Path>,
settings: &Settings,
) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = vec![];
// flake8-no-pep420
if settings.rules.enabled(&Rule::ImplicitNamespacePackage) {
if let Some(diagnostic) = implicit_namespace_package(path) {
if let Some(diagnostic) = implicit_namespace_package(path, package) {
diagnostics.push(diagnostic);
}
}

View File

@@ -16,6 +16,8 @@ use crate::directives::Directives;
use crate::doc_lines::{doc_lines_from_ast, doc_lines_from_tokens};
use crate::message::{Message, Source};
use crate::noqa::add_noqa;
#[cfg(test)]
use crate::packaging::detect_package_root;
use crate::registry::{Diagnostic, LintSource, Rule};
use crate::settings::{flags, Settings};
use crate::source_code::{Indexer, Locator, Stylist};
@@ -69,7 +71,7 @@ pub fn check_path(
.iter_enabled()
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Filesystem))
{
diagnostics.extend(check_file_path(path, settings));
diagnostics.extend(check_file_path(path, package, settings));
}
// Run the AST-based rules.
@@ -395,7 +397,8 @@ pub fn test_path(path: &Path, settings: &Settings) -> Result<Vec<Diagnostic>> {
directives::extract_directives(&tokens, directives::Flags::from_settings(settings));
let mut diagnostics = check_path(
path,
None,
path.parent()
.and_then(|parent| detect_package_root(parent, &settings.namespace_packages)),
&contents,
tokens,
&locator,

View File

@@ -3,7 +3,7 @@ pub(crate) mod rules;
#[cfg(test)]
mod tests {
use std::path::Path;
use std::path::{Path, PathBuf};
use anyhow::Result;
use test_case::test_case;
@@ -12,11 +12,12 @@ mod tests {
use crate::registry::Rule;
use crate::settings::Settings;
#[test_case(Path::new("test_pass"); "INP001_0")]
#[test_case(Path::new("test_pass_init"); "INP001_0")]
#[test_case(Path::new("test_fail_empty"); "INP001_1")]
#[test_case(Path::new("test_fail_nonempty"); "INP001_2")]
#[test_case(Path::new("test_fail_shebang"); "INP001_3")]
#[test_case(Path::new("test_ignored"); "INP001_4")]
#[test_case(Path::new("test_pass_namespace_package"); "INP001_5")]
fn test_flake8_no_pep420(path: &Path) -> Result<()> {
let snapshot = format!("{}", path.to_string_lossy());
let diagnostics = test_path(
@@ -24,7 +25,12 @@ mod tests {
.join(path)
.join("example.py")
.as_path(),
&Settings::for_rule(Rule::ImplicitNamespacePackage),
&Settings {
namespace_packages: vec![PathBuf::from(
"./resources/test/fixtures/flake8_no_pep420/test_pass_namespace_package",
)],
..Settings::for_rule(Rule::ImplicitNamespacePackage)
},
)?;
insta::assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())

View File

@@ -5,14 +5,13 @@ use crate::registry::Diagnostic;
use crate::{fs, violations};
/// INP001
pub fn implicit_namespace_package(path: &Path) -> Option<Diagnostic> {
if let Some(parent) = path.parent() {
if !parent.join("__init__.py").as_path().exists() {
return Some(Diagnostic::new(
violations::ImplicitNamespacePackage(fs::relativize_path(path).to_string()),
Range::default(),
));
}
pub fn implicit_namespace_package(path: &Path, package: Option<&Path>) -> Option<Diagnostic> {
if package.is_none() {
Some(Diagnostic::new(
violations::ImplicitNamespacePackage(fs::relativize_path(path).to_string()),
Range::default(),
))
} else {
None
}
None
}

View File

@@ -0,0 +1,6 @@
---
source: src/rules/flake8_no_pep420/mod.rs
expression: diagnostics
---
[]