Update deprecation warnings (#15867)

# Description
- Use #15770 to
  - improve `get --sensitive` deprecation warning
  - add deprecation warning for `filter`
- refactor `filter` to use `where` as its implementation
- replace usages of `filter` with `where` in `std`

# User-Facing Changes
- `get --sensitive` will raise a warning only once, during parsing
whereas before it was raised during runtime for each usage.
- using `filter` will raise a deprecation warning, once

# Tests + Formatting
No existing test broke or required tweaking. Additional tests covering
this case was added.
- 🟢 toolkit fmt
- 🟢 toolkit clippy
- 🟢 toolkit test
- 🟢 toolkit test stdlib

# After Submitting
N/A

---------

Co-authored-by: Bahex <17417311+Bahex@users.noreply.github.com>
This commit is contained in:
Bahex 2025-06-01 19:21:07 +03:00 committed by GitHub
parent cfbe835910
commit ad9f051d61
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 41 additions and 102 deletions

View File

@ -1,6 +1,5 @@
use super::utils::chain_error_with_input;
use nu_engine::{ClosureEval, ClosureEvalOnce, command_prelude::*};
use nu_protocol::engine::Closure;
use nu_engine::command_prelude::*;
use nu_protocol::{DeprecationEntry, DeprecationType, ReportMode};
#[derive(Clone)]
pub struct Filter;
@ -15,8 +14,8 @@ impl Command for Filter {
}
fn extra_description(&self) -> &str {
r#"This command works similar to 'where' but allows reading the predicate closure from
a variable. On the other hand, the "row condition" syntax is not supported."#
r#"This command works similar to 'where' but can only use a closure as a predicate.
The "row condition" syntax is not supported."#
}
fn signature(&self) -> nu_protocol::Signature {
@ -47,80 +46,20 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let closure: Closure = call.req(engine_state, stack, 0)?;
use super::where_::Where;
<Where as Command>::run(&Where, engine_state, stack, call, input)
}
let metadata = input.metadata();
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream(..) => {
let mut closure = ClosureEval::new(engine_state, stack, closure);
Ok(input
.into_iter()
.filter_map(move |value| {
match closure
.run_with_value(value.clone())
.and_then(|data| data.into_value(head))
{
Ok(cond) => cond.is_true().then_some(value),
Err(err) => {
let span = value.span();
let err = chain_error_with_input(err, value.is_error(), span);
Some(Value::error(err, span))
}
}
})
.into_pipeline_data(head, engine_state.signals().clone()))
fn deprecation_info(&self) -> Vec<nu_protocol::DeprecationEntry> {
vec![
DeprecationEntry {
ty: DeprecationType::Command,
report_mode: ReportMode::FirstUse,
since: Some("0.105.0".into()),
expected_removal: None,
help: Some("`where` command can be used instead, as it can now read the predicate closure from a variable".into()),
}
PipelineData::ByteStream(stream, ..) => {
if let Some(chunks) = stream.chunks() {
let mut closure = ClosureEval::new(engine_state, stack, closure);
Ok(chunks
.into_iter()
.filter_map(move |value| {
let value = match value {
Ok(value) => value,
Err(err) => return Some(Value::error(err, head)),
};
match closure
.run_with_value(value.clone())
.and_then(|data| data.into_value(head))
{
Ok(cond) => cond.is_true().then_some(value),
Err(err) => {
let span = value.span();
let err = chain_error_with_input(err, value.is_error(), span);
Some(Value::error(err, span))
}
}
})
.into_pipeline_data(head, engine_state.signals().clone()))
} else {
Ok(PipelineData::Empty)
}
}
// This match allows non-iterables to be accepted,
// which is currently considered undesirable (Nov 2022).
PipelineData::Value(value, ..) => {
let result = ClosureEvalOnce::new(engine_state, stack, closure)
.run_with_value(value.clone())
.and_then(|data| data.into_value(head));
Ok(match result {
Ok(cond) => cond.is_true().then_some(value),
Err(err) => {
let span = value.span();
let err = chain_error_with_input(err, value.is_error(), span);
Some(Value::error(err, span))
}
}
.into_pipeline_data(head, engine_state.signals().clone()))
}
}
.map(|data| data.set_metadata(metadata))
]
}
fn examples(&self) -> Vec<Example> {

View File

@ -1,7 +1,7 @@
use std::borrow::Cow;
use nu_engine::command_prelude::*;
use nu_protocol::{Signals, ast::PathMember, report_shell_warning};
use nu_protocol::{DeprecationEntry, DeprecationType, ReportMode, Signals, ast::PathMember};
#[derive(Clone)]
pub struct Get;
@ -132,19 +132,7 @@ If multiple cell paths are given, this will produce a list of values."#
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
let rest: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
let sensitive_span = call.get_flag_span(stack, "sensitive");
let metadata = input.metadata();
if let Some(span) = sensitive_span {
report_shell_warning(
engine_state,
&ShellError::Deprecated {
deprecated: "sensitive flag",
suggestion: "",
span,
help: Some("cell-paths are case-sensitive by default"),
},
);
}
action(
input,
cell_path,
@ -155,6 +143,18 @@ If multiple cell paths are given, this will produce a list of values."#
)
.map(|x| x.set_metadata(metadata))
}
fn deprecation_info(&self) -> Vec<DeprecationEntry> {
vec![
DeprecationEntry {
ty: DeprecationType::Flag("sensitive".into()),
report_mode: ReportMode::FirstUse,
since: Some("0.105.0".into()),
expected_removal: None,
help: Some("Cell-paths are now case-sensitive by default.\nTo access fields case-insensitively, add `!` after the relevant path member.".into())
}
]
}
}
fn action(

View File

@ -14,5 +14,5 @@ fn filter_with_return_in_closure() {
));
assert_eq!(actual.out, "[2, 4, 6, 8, 10]");
assert!(actual.err.is_empty());
assert!(actual.err.contains("deprecated"));
}

View File

@ -18,7 +18,7 @@
export def find [
fn: closure # the closure used to perform the search
] {
filter {|e| try {do $fn $e} } | try { first }
where {|e| try {do $fn $e} } | try { first }
}
# Returns the index of the first element that matches the predicate or -1 if none
@ -87,7 +87,7 @@ export def scan [ # -> list<any>
#
# This is equivalent to
#
# $in | each $fn | filter $fn
# $in | each $fn | where $fn
@example "Get the squares of elements that can be squared" {
[2 5 "4" 7] | iter filter-map {|e| $e ** 2}
} --result [4, 25, 49]
@ -101,7 +101,7 @@ export def filter-map [
null
}
}
| filter {|e|
| where {|e|
$e != null
}
}

View File

@ -62,7 +62,7 @@ def xupdate-string-step [ step: string rest: list updater: closure ] {
let input = $in
# Get a list of elements to be updated and their indices
let to_update = ($input.content | enumerate | filter {|it|
let to_update = ($input.content | enumerate | where {|it|
let item = $it.item
$step == '*' or $item.tag == $step
})

View File

@ -333,20 +333,20 @@ export def run-tests [
commands: (get-annotated $row.name)
}
}
| filter {|x| ($x.commands|length) > 0}
| where {|x| ($x.commands|length) > 0}
| upsert commands {|module|
$module.commands
| create-test-record
}
| flatten
| filter {|x| ($x.test|length) > 0}
| filter {|x| if ($exclude_module|is-empty) {true} else {$x.name !~ $exclude_module}}
| filter {|x| if ($test|is-empty) {true} else {$x.test|any {|y| $y =~ $test}}}
| filter {|x| if ($module|is-empty) {true} else {$module == $x.name}}
| where {|x| ($x.test|length) > 0}
| where {|x| if ($exclude_module|is-empty) {true} else {$x.name !~ $exclude_module}}
| where {|x| if ($test|is-empty) {true} else {$x.test|any {|y| $y =~ $test}}}
| where {|x| if ($module|is-empty) {true} else {$module == $x.name}}
| update test {|x|
$x.test
| filter {|y| if ($test|is-empty) {true} else {$y =~ $test}}
| filter {|y| if ($exclude|is-empty) {true} else {$y !~ $exclude}}
| where {|y| if ($test|is-empty) {true} else {$y =~ $test}}
| where {|y| if ($exclude|is-empty) {true} else {$y !~ $exclude}}
}
)
if $list {