mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 18:15:04 +02:00
refactor(get,select,reject)!: deprecate --ignore-errors in favor of --optional (#16007)
# Description As decided on the team meeting on 2025-06-19, rename `--ignore-errors (-i)` to `--optional (-o)` with a (currently) indefinite grace period. After `--ignore-errors (-i)` is removed, the short flag `-i` can be used for `--ignore-case` (not implemented as of this PR) # User-Facing Changes `get`/`select`/`reject`: rename `--ignore-errors (-i)` to `--optional (-o)` to better reflect its behavior. # Tests + Formatting - 🟢 toolkit fmt - 🟢 toolkit clippy - 🟢 toolkit test - 🟢 toolkit test stdlib # After Submitting Update docs and inform third parties that integrate with nushell. --------- Co-authored-by: Bahex <17417311+Bahex@users.noreply.github.com>
This commit is contained in:
@ -82,7 +82,7 @@ impl Command for Default {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Get the env value of `MY_ENV` with a default value 'abc' if not present",
|
description: "Get the env value of `MY_ENV` with a default value 'abc' if not present",
|
||||||
example: "$env | get --ignore-errors MY_ENV | default 'abc'",
|
example: "$env | get --optional MY_ENV | default 'abc'",
|
||||||
result: Some(Value::test_string("abc")),
|
result: Some(Value::test_string("abc")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
|
@ -40,9 +40,14 @@ If multiple cell paths are given, this will produce a list of values."#
|
|||||||
"The cell path to the data.",
|
"The cell path to the data.",
|
||||||
)
|
)
|
||||||
.rest("rest", SyntaxShape::CellPath, "Additional cell paths.")
|
.rest("rest", SyntaxShape::CellPath, "Additional cell paths.")
|
||||||
|
.switch(
|
||||||
|
"optional",
|
||||||
|
"make all cell path members optional (returns `null` for missing values)",
|
||||||
|
Some('o'),
|
||||||
|
)
|
||||||
.switch(
|
.switch(
|
||||||
"ignore-errors",
|
"ignore-errors",
|
||||||
"ignore missing data (make all cell path members optional)",
|
"ignore missing data (make all cell path members optional) (deprecated)",
|
||||||
Some('i'),
|
Some('i'),
|
||||||
)
|
)
|
||||||
.switch(
|
.switch(
|
||||||
@ -131,13 +136,14 @@ If multiple cell paths are given, this will produce a list of values."#
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
||||||
let rest: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
let rest: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
||||||
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
|
let optional = call.has_flag(engine_state, stack, "optional")?
|
||||||
|
|| call.has_flag(engine_state, stack, "ignore-errors")?;
|
||||||
let metadata = input.metadata();
|
let metadata = input.metadata();
|
||||||
action(
|
action(
|
||||||
input,
|
input,
|
||||||
cell_path,
|
cell_path,
|
||||||
rest,
|
rest,
|
||||||
ignore_errors,
|
optional,
|
||||||
engine_state.signals().clone(),
|
engine_state.signals().clone(),
|
||||||
call.head,
|
call.head,
|
||||||
)
|
)
|
||||||
@ -152,6 +158,13 @@ If multiple cell paths are given, this will produce a list of values."#
|
|||||||
since: Some("0.105.0".into()),
|
since: Some("0.105.0".into()),
|
||||||
expected_removal: None,
|
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())
|
help: Some("Cell-paths are now case-sensitive by default.\nTo access fields case-insensitively, add `!` after the relevant path member.".into())
|
||||||
|
},
|
||||||
|
DeprecationEntry {
|
||||||
|
ty: DeprecationType::Flag("ignore-errors".into()),
|
||||||
|
report_mode: ReportMode::FirstUse,
|
||||||
|
since: Some("0.106.0".into()),
|
||||||
|
expected_removal: None,
|
||||||
|
help: Some("This flag has been renamed to `--optional (-o)` to better reflect its behavior.".into())
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -161,11 +174,11 @@ fn action(
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
mut cell_path: CellPath,
|
mut cell_path: CellPath,
|
||||||
mut rest: Vec<CellPath>,
|
mut rest: Vec<CellPath>,
|
||||||
ignore_errors: bool,
|
optional: bool,
|
||||||
signals: Signals,
|
signals: Signals,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
if ignore_errors {
|
if optional {
|
||||||
cell_path.make_optional();
|
cell_path.make_optional();
|
||||||
for path in &mut rest {
|
for path in &mut rest {
|
||||||
path.make_optional();
|
path.make_optional();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{ast::PathMember, casing::Casing};
|
use nu_protocol::{DeprecationEntry, DeprecationType, ReportMode, ast::PathMember, casing::Casing};
|
||||||
use std::{cmp::Reverse, collections::HashSet};
|
use std::{cmp::Reverse, collections::HashSet};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -17,9 +17,10 @@ impl Command for Reject {
|
|||||||
(Type::table(), Type::table()),
|
(Type::table(), Type::table()),
|
||||||
(Type::list(Type::Any), Type::list(Type::Any)),
|
(Type::list(Type::Any), Type::list(Type::Any)),
|
||||||
])
|
])
|
||||||
|
.switch("optional", "make all cell path members optional", Some('o'))
|
||||||
.switch(
|
.switch(
|
||||||
"ignore-errors",
|
"ignore-errors",
|
||||||
"ignore missing data (make all cell path members optional)",
|
"ignore missing data (make all cell path members optional) (deprecated)",
|
||||||
Some('i'),
|
Some('i'),
|
||||||
)
|
)
|
||||||
.rest(
|
.rest(
|
||||||
@ -90,8 +91,9 @@ impl Command for Reject {
|
|||||||
}
|
}
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
|
|
||||||
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
|
let optional = call.has_flag(engine_state, stack, "optional")?
|
||||||
if ignore_errors {
|
|| call.has_flag(engine_state, stack, "ignore-errors")?;
|
||||||
|
if optional {
|
||||||
for cell_path in &mut new_columns {
|
for cell_path in &mut new_columns {
|
||||||
cell_path.make_optional();
|
cell_path.make_optional();
|
||||||
}
|
}
|
||||||
@ -100,6 +102,19 @@ impl Command for Reject {
|
|||||||
reject(engine_state, span, input, new_columns)
|
reject(engine_state, span, input, new_columns)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deprecation_info(&self) -> Vec<DeprecationEntry> {
|
||||||
|
vec![DeprecationEntry {
|
||||||
|
ty: DeprecationType::Flag("ignore-errors".into()),
|
||||||
|
report_mode: ReportMode::FirstUse,
|
||||||
|
since: Some("0.106.0".into()),
|
||||||
|
expected_removal: None,
|
||||||
|
help: Some(
|
||||||
|
"This flag has been renamed to `--optional (-o)` to better reflect its behavior."
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{PipelineIterator, ast::PathMember, casing::Casing};
|
use nu_protocol::{
|
||||||
|
DeprecationEntry, DeprecationType, PipelineIterator, ReportMode, ast::PathMember,
|
||||||
|
casing::Casing,
|
||||||
|
};
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -18,9 +21,14 @@ impl Command for Select {
|
|||||||
(Type::table(), Type::table()),
|
(Type::table(), Type::table()),
|
||||||
(Type::List(Box::new(Type::Any)), Type::Any),
|
(Type::List(Box::new(Type::Any)), Type::Any),
|
||||||
])
|
])
|
||||||
|
.switch(
|
||||||
|
"optional",
|
||||||
|
"make all cell path members optional (returns `null` for missing values)",
|
||||||
|
Some('o'),
|
||||||
|
)
|
||||||
.switch(
|
.switch(
|
||||||
"ignore-errors",
|
"ignore-errors",
|
||||||
"ignore missing data (make all cell path members optional)",
|
"ignore missing data (make all cell path members optional) (deprecated)",
|
||||||
Some('i'),
|
Some('i'),
|
||||||
)
|
)
|
||||||
.rest(
|
.rest(
|
||||||
@ -100,10 +108,11 @@ produce a table, a list will produce a list, and a record will produce a record.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
|
let optional = call.has_flag(engine_state, stack, "optional")?
|
||||||
|
|| call.has_flag(engine_state, stack, "ignore-errors")?;
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
|
|
||||||
if ignore_errors {
|
if optional {
|
||||||
for cell_path in &mut new_columns {
|
for cell_path in &mut new_columns {
|
||||||
cell_path.make_optional();
|
cell_path.make_optional();
|
||||||
}
|
}
|
||||||
@ -112,6 +121,19 @@ produce a table, a list will produce a list, and a record will produce a record.
|
|||||||
select(engine_state, span, new_columns, input)
|
select(engine_state, span, new_columns, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deprecation_info(&self) -> Vec<DeprecationEntry> {
|
||||||
|
vec![DeprecationEntry {
|
||||||
|
ty: DeprecationType::Flag("ignore-errors".into()),
|
||||||
|
report_mode: ReportMode::FirstUse,
|
||||||
|
since: Some("0.106.0".into()),
|
||||||
|
expected_removal: None,
|
||||||
|
help: Some(
|
||||||
|
"This flag has been renamed to `--optional (-o)` to better reflect its behavior."
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
|
@ -31,7 +31,7 @@ fn adds_row_data_if_column_missing() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_after_empty_filter() {
|
fn default_after_empty_filter() {
|
||||||
let actual = nu!("[a b] | where $it == 'c' | get -i 0 | default 'd'");
|
let actual = nu!("[a b] | where $it == 'c' | get -o 0 | default 'd'");
|
||||||
|
|
||||||
assert_eq!(actual.out, "d");
|
assert_eq!(actual.out, "d");
|
||||||
}
|
}
|
||||||
|
@ -196,14 +196,14 @@ fn get_does_not_delve_too_deep_in_nested_lists() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ignore_errors_works() {
|
fn ignore_errors_works() {
|
||||||
let actual = nu!(r#" let path = "foo"; {} | get -i $path | to nuon "#);
|
let actual = nu!(r#" let path = "foo"; {} | get -o $path | to nuon "#);
|
||||||
|
|
||||||
assert_eq!(actual.out, "null");
|
assert_eq!(actual.out, "null");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ignore_multiple() {
|
fn ignore_multiple() {
|
||||||
let actual = nu!(r#"[[a];[b]] | get -i c d | to nuon"#);
|
let actual = nu!(r#"[[a];[b]] | get -o c d | to nuon"#);
|
||||||
|
|
||||||
assert_eq!(actual.out, "[[null], [null]]");
|
assert_eq!(actual.out, "[[null], [null]]");
|
||||||
}
|
}
|
||||||
|
@ -174,14 +174,14 @@ fn reject_multiple_rows_descending() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ignore_errors_flag() {
|
fn test_ignore_errors_flag() {
|
||||||
let actual = nu!("[[a, b]; [1, 2], [3, 4], [5, 6]] | reject 5 -i | to nuon");
|
let actual = nu!("[[a, b]; [1, 2], [3, 4], [5, 6]] | reject 5 -o | to nuon");
|
||||||
assert_eq!(actual.out, "[[a, b]; [1, 2], [3, 4], [5, 6]]");
|
assert_eq!(actual.out, "[[a, b]; [1, 2], [3, 4], [5, 6]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ignore_errors_flag_var() {
|
fn test_ignore_errors_flag_var() {
|
||||||
let actual =
|
let actual =
|
||||||
nu!("let arg = [5 c]; [[a, b]; [1, 2], [3, 4], [5, 6]] | reject ...$arg -i | to nuon");
|
nu!("let arg = [5 c]; [[a, b]; [1, 2], [3, 4], [5, 6]] | reject ...$arg -o | to nuon");
|
||||||
assert_eq!(actual.out, "[[a, b]; [1, 2], [3, 4], [5, 6]]");
|
assert_eq!(actual.out, "[[a, b]; [1, 2], [3, 4], [5, 6]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ fn select_repeated_column() {
|
|||||||
fn ignore_errors_works() {
|
fn ignore_errors_works() {
|
||||||
let actual = nu!(r#"
|
let actual = nu!(r#"
|
||||||
let path = "foo";
|
let path = "foo";
|
||||||
[{}] | select -i $path | to nuon
|
[{}] | select -o $path | to nuon
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
assert_eq!(actual.out, "[[foo]; [null]]");
|
assert_eq!(actual.out, "[[foo]; [null]]");
|
||||||
|
@ -326,7 +326,7 @@ fn from_csv_text_with_missing_columns_to_table() {
|
|||||||
r#"
|
r#"
|
||||||
open los_tres_caballeros.txt
|
open los_tres_caballeros.txt
|
||||||
| from csv --flexible
|
| from csv --flexible
|
||||||
| get -i rusty_luck
|
| get -o rusty_luck
|
||||||
| compact
|
| compact
|
||||||
| length
|
| length
|
||||||
"#
|
"#
|
||||||
|
@ -245,7 +245,7 @@ fn from_tsv_text_with_missing_columns_to_table() {
|
|||||||
r#"
|
r#"
|
||||||
open los_tres_caballeros.txt
|
open los_tres_caballeros.txt
|
||||||
| from tsv --flexible
|
| from tsv --flexible
|
||||||
| get -i rusty_luck
|
| get -o rusty_luck
|
||||||
| compact
|
| compact
|
||||||
| length
|
| length
|
||||||
"#
|
"#
|
||||||
|
@ -42,7 +42,7 @@ def get-annotated [
|
|||||||
| from nuon
|
| from nuon
|
||||||
| each {|e|
|
| each {|e|
|
||||||
# filter commands with test attributes, and map attributes to annotation name
|
# filter commands with test attributes, and map attributes to annotation name
|
||||||
let test_attributes = $e.attributes.name | each {|x| $valid_annotations | get -i $x }
|
let test_attributes = $e.attributes.name | each {|x| $valid_annotations | get -o $x }
|
||||||
if ($test_attributes | is-not-empty) {
|
if ($test_attributes | is-not-empty) {
|
||||||
$e | update attributes $test_attributes.0
|
$e | update attributes $test_attributes.0
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ def run [
|
|||||||
} else {
|
} else {
|
||||||
^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) "test message"'
|
^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) "test message"'
|
||||||
}
|
}
|
||||||
| complete | get --ignore-errors stderr
|
| complete | get --optional stderr
|
||||||
}
|
}
|
||||||
|
|
||||||
def "assert no message" [
|
def "assert no message" [
|
||||||
|
@ -19,7 +19,7 @@ def run-command [
|
|||||||
} else {
|
} else {
|
||||||
^$nu.current-exe --no-config-file --commands $'use std/log; NU_LOG_LEVEL=($system_level) log custom "($message)" "($format)" ($log_level) --level-prefix "($level_prefix)" --ansi "($ansi)"'
|
^$nu.current-exe --no-config-file --commands $'use std/log; NU_LOG_LEVEL=($system_level) log custom "($message)" "($format)" ($log_level) --level-prefix "($level_prefix)" --ansi "($ansi)"'
|
||||||
}
|
}
|
||||||
| complete | get --ignore-errors stderr
|
| complete | get --optional stderr
|
||||||
}
|
}
|
||||||
|
|
||||||
@test
|
@test
|
||||||
|
@ -16,7 +16,7 @@ def run-command [
|
|||||||
} else {
|
} else {
|
||||||
^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) --format "($format)" "($message)"'
|
^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) --format "($format)" "($message)"'
|
||||||
}
|
}
|
||||||
| complete | get --ignore-errors stderr
|
| complete | get --optional stderr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ export def "update" [
|
|||||||
let input = $in
|
let input = $in
|
||||||
match ($input | describe | str replace --regex '<.*' '') {
|
match ($input | describe | str replace --regex '<.*' '') {
|
||||||
record => {
|
record => {
|
||||||
if ($input | get -i $field) != null {
|
if ($input | get -o $field) != null {
|
||||||
$input | orig update $field $value
|
$input | orig update $field $value
|
||||||
} else { $input }
|
} else { $input }
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user