forked from extern/nushell
Compare commits
124 Commits
patch-rele
...
revert-113
Author | SHA1 | Date | |
---|---|---|---|
286a6b021c | |||
50102bf69b | |||
156232fe08 | |||
0a3761a594 | |||
44dc890124 | |||
6ead98effb | |||
d5f76c02f0 | |||
fd77114d82 | |||
78f52e8b66 | |||
5b01685fc3 | |||
c2b684464f | |||
fd56768fdc | |||
070afa4528 | |||
23fec8eb0d | |||
c9841f67e9 | |||
76482cc1b2 | |||
d43f4253e8 | |||
0fba08808c | |||
b3a52a247f | |||
4763801cb2 | |||
ecb3b3a364 | |||
3e5f81ae14 | |||
ca05553fc6 | |||
fa5d7babb9 | |||
94b27267fd | |||
d1390ac95b | |||
d717e8faeb | |||
a95a4505ef | |||
b03f1efac4 | |||
5d5088b5d5 | |||
c1c73811d5 | |||
51bf8d9f6a | |||
858c93d2e5 | |||
31146a7591 | |||
05d7d6d6ad | |||
fb3350ebc3 | |||
2ffe30ecf0 | |||
f8dc3421b0 | |||
c1a30ac60f | |||
fc06afd051 | |||
c9aa6ba0f3 | |||
f8c82588b6 | |||
67eec92e76 | |||
b227eea668 | |||
58d002d469 | |||
5d283755e3 | |||
35e8db160d | |||
7d8df4ba9e | |||
f36c055c50 | |||
76bdda1178 | |||
5c07e82fc0 | |||
6ea5bdcf47 | |||
15c7e1b725 | |||
e5d9f405db | |||
80881c75f9 | |||
250ee62e16 | |||
54d73748e4 | |||
d08e254d16 | |||
7f771babb7 | |||
b9b9eaaca5 | |||
0303d709e6 | |||
0e1322e6d6 | |||
e290fa0e68 | |||
112306aab5 | |||
98952082ae | |||
8386bc0919 | |||
182b0ab4fb | |||
fa83458a6d | |||
54398f9546 | |||
077d1c8125 | |||
1ff8c2d81d | |||
d77f1753c2 | |||
85c6047b71 | |||
d37893cca0 | |||
95ac436d26 | |||
c2a46070aa | |||
57808ca7cc | |||
6cfe35eb7e | |||
b2734db015 | |||
823e578c46 | |||
95a745e622 | |||
776df7cd93 | |||
d5677625a7 | |||
64288b4350 | |||
a42fd3611a | |||
e36f69bf3c | |||
5ad7b8f029 | |||
ffb80b8873 | |||
177e800a07 | |||
a7e8970383 | |||
a324a50bb7 | |||
0578cf85ac | |||
1b54dd5418 | |||
8ad5d8bb6a | |||
869b01205c | |||
f5b2f5a9ee | |||
adfa4d00c0 | |||
12effd9b4e | |||
c26fca7419 | |||
da59dfe7d2 | |||
08715e6308 | |||
07d7899a97 | |||
494a5a5286 | |||
f41c93b2d3 | |||
5063e01c12 | |||
d1137cc700 | |||
3966c0a9fd | |||
dbdb1f6600 | |||
84cdc0d521 | |||
ab59dab129 | |||
e0c8a3d14c | |||
e93e51d672 | |||
4205edbc70 | |||
80bee40807 | |||
461837773b | |||
52d4259f58 | |||
274a8366c6 | |||
a1dfc35968 | |||
5886a74ccc | |||
4367aa9f58 | |||
e9c298713e | |||
c110ddff66 | |||
a806717f35 | |||
2b5f1ee5b3 |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -41,7 +41,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
with:
|
||||
rustflags: ""
|
||||
|
||||
@ -85,7 +85,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
with:
|
||||
rustflags: ""
|
||||
|
||||
@ -106,7 +106,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
with:
|
||||
rustflags: ""
|
||||
|
||||
@ -117,7 +117,7 @@ jobs:
|
||||
run: nu -c 'use std testing; testing run-tests --path crates/nu-std'
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
@ -141,7 +141,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
with:
|
||||
rustflags: ""
|
||||
|
||||
|
4
.github/workflows/nightly-build.yml
vendored
4
.github/workflows/nightly-build.yml
vendored
@ -135,7 +135,7 @@ jobs:
|
||||
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
||||
with:
|
||||
rustflags: ''
|
||||
@ -249,7 +249,7 @@ jobs:
|
||||
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
||||
with:
|
||||
rustflags: ''
|
||||
|
4
.github/workflows/release-pkg.nu
vendored
4
.github/workflows/release-pkg.nu
vendored
@ -138,8 +138,6 @@ print $'(char nl)Copying release files...'; hr-line
|
||||
|
||||
> register ./nu_plugin_query" | save $'($dist)/README.txt' -f
|
||||
[LICENSE $executable] | each {|it| cp -rv $it $dist } | flatten
|
||||
# Sleep a few seconds to make sure the cp process finished successfully
|
||||
sleep 3sec
|
||||
|
||||
print $'(char nl)Check binary release version detail:'; hr-line
|
||||
let ver = if $os == 'windows-latest' {
|
||||
@ -148,7 +146,7 @@ let ver = if $os == 'windows-latest' {
|
||||
(do -i { ./output/nu -c 'version' }) | str join
|
||||
}
|
||||
if ($ver | str trim | is-empty) {
|
||||
print $'(ansi r)Incompatible nu binary...(ansi reset)'
|
||||
print $'(ansi r)Incompatible Nu binary: The binary cross compiled is not runnable on current arch...(ansi reset)'
|
||||
} else { print $ver }
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -79,7 +79,7 @@ jobs:
|
||||
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
||||
with:
|
||||
rustflags: ''
|
||||
@ -170,7 +170,7 @@ jobs:
|
||||
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
|
||||
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
||||
with:
|
||||
rustflags: ''
|
||||
|
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
@ -10,6 +10,6 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check spelling
|
||||
uses: crate-ci/typos@v1.16.23
|
||||
uses: crate-ci/typos@v1.16.24
|
||||
with:
|
||||
config: ./.github/.typos.toml
|
||||
|
@ -10,11 +10,16 @@ Welcome to Nushell and thank you for considering contributing!
|
||||
- [Useful commands](#useful-commands)
|
||||
- [Debugging tips](#debugging-tips)
|
||||
- [Git etiquette](#git-etiquette)
|
||||
- [Our Rust style](#our-rust-style)
|
||||
- [Generally discouraged](#generally-discouraged)
|
||||
- [Things we want to get better at](#things-we-want-to-get-better-at)
|
||||
- [License](#license)
|
||||
|
||||
## Other helpful resources
|
||||
|
||||
More resources can be found in the nascent [developer documentation](devdocs/README.md) in this repo.
|
||||
|
||||
- [Developer FAQ](FAQ.md)
|
||||
- [Platform support policy](PLATFORM_SUPPORT.md)
|
||||
- [Our Rust style](devdocs/rust_style.md)
|
||||
|
||||
## Proposing design changes
|
||||
|
||||
First of all, before diving into the code, if you want to create a new feature, change something significantly, and especially if the change is user-facing, it is a good practice to first get an approval from the core team before starting to work on it.
|
||||
@ -63,74 +68,74 @@ Read cargo's documentation for more details: https://doc.rust-lang.org/cargo/ref
|
||||
|
||||
- Build and run Nushell:
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo run
|
||||
```
|
||||
|
||||
- Build and run with dataframe support.
|
||||
```shell
|
||||
```nushell
|
||||
cargo run --features=dataframe
|
||||
```
|
||||
|
||||
- Run Clippy on Nushell:
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo clippy --workspace -- -D warnings -D clippy::unwrap_used
|
||||
```
|
||||
or via the `toolkit.nu` command:
|
||||
```shell
|
||||
```nushell
|
||||
use toolkit.nu clippy
|
||||
clippy
|
||||
```
|
||||
|
||||
- Run all tests:
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
along with dataframe tests
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo test --workspace --features=dataframe
|
||||
```
|
||||
or via the `toolkit.nu` command:
|
||||
```shell
|
||||
```nushell
|
||||
use toolkit.nu test
|
||||
test
|
||||
```
|
||||
|
||||
- Run all tests for a specific command
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo test --package nu-cli --test main -- commands::<command_name_here>
|
||||
```
|
||||
|
||||
- Check to see if there are code formatting issues
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo fmt --all -- --check
|
||||
```
|
||||
or via the `toolkit.nu` command:
|
||||
```shell
|
||||
```nushell
|
||||
use toolkit.nu fmt
|
||||
fmt --check
|
||||
```
|
||||
|
||||
- Format the code in the project
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo fmt --all
|
||||
```
|
||||
or via the `toolkit.nu` command:
|
||||
```shell
|
||||
```nushell
|
||||
use toolkit.nu fmt
|
||||
fmt
|
||||
```
|
||||
|
||||
- Set up `git` hooks to check formatting and run `clippy` before committing and pushing:
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
use toolkit.nu setup-git-hooks
|
||||
setup-git-hooks
|
||||
```
|
||||
@ -140,12 +145,12 @@ Read cargo's documentation for more details: https://doc.rust-lang.org/cargo/ref
|
||||
|
||||
- To view verbose logs when developing, enable the `trace` log level.
|
||||
|
||||
```shell
|
||||
```nushell
|
||||
cargo run --release -- --log-level trace
|
||||
```
|
||||
|
||||
- To redirect trace logs to a file, enable the `--log-target file` switch.
|
||||
```shell
|
||||
```nushell
|
||||
cargo run --release -- --log-level trace --log-target file
|
||||
open $"($nu.temp-path)/nu-($nu.pid).log"
|
||||
```
|
||||
@ -237,51 +242,6 @@ You can help us to make the review process a smooth experience:
|
||||
- Feel free to notify your reviewers or affected PR authors if your change might cause larger conflicts with another change.
|
||||
- During the rollup of multiple PRs, we may choose to resolve merge conflicts and CI failures ourselves. (Allow maintainers to push to your branch to enable us to do this quickly.)
|
||||
|
||||
## Our Rust style
|
||||
To make the collaboration on a project the scale of Nushell easy, we want to work towards a style of Rust code that can easily be understood by all of our contributors. We conservatively rely on most of [`clippy`s suggestions](https://github.com/rust-lang/rust-clippy) to get to the holy grail of "idiomatic" code. Good code in our eyes is not the most clever use of all available language features or with the most unique personal touch but readable and strikes a balance between being concise, and also unsurprising and explicit in the places where it matters.
|
||||
One example of this philosophy is that we generally avoid to fight the borrow-checker in our data model but rather try to get to a correct and simple solution first and then figure out where we should reuse data to achieve the necessary performance. As we are still pre-1.0 this served us well to be able to quickly refactor or change larger parts of the code base.
|
||||
|
||||
### Generally discouraged
|
||||
#### `+nightly` language features or things only available in the most recent `+stable`
|
||||
To make life for the people easier that maintain the Nushell packages in various distributions with their own release cycle of `rustc` we typically rely on slightly older Rust versions. We do not make explicit guarantees how far back in the past we live but you can find out in our [`rust-toolchain.toml`](https://github.com/nushell/nushell/blob/main/rust-toolchain.toml)
|
||||
(As a rule of thumb this has been typically been approximately 2 releases behind the newest stable compiler.)
|
||||
The use of nightly features is prohibited.
|
||||
|
||||
#### Panicking
|
||||
As Nushell aims to provide a reliable foundational way for folks to interact with their computer, we cannot carelessly crash the execution of their work by panicking Nushell.
|
||||
Thus panicking is not an allowed error handling strategy for anything that could be triggered by user input OR behavior of the outside system. If Nushell panics this is a bug or we are against all odds already in an unrecoverable state (The system stopped cooperating, we went out of memory). The use of `.unwrap()` is thus outright banned and any uses of `.expect()` or related panicking macros like `unreachable!` should include a helpful description which assumptions have been violated.
|
||||
|
||||
#### `unsafe` code
|
||||
For any use of `unsafe` code we need to require even higher standards and additional review. If you add or alter `unsafe` blocks you have to be familiar with the promises you need to uphold as found in the [Rustonomicon](https://doc.rust-lang.org/nomicon/intro.html). All `unsafe` uses should include `// SAFETY:` comments explaining how the invariants are upheld and thus alerting you what to watch out for when making a change.
|
||||
##### FFI with system calls and the outside world
|
||||
As a shell Nushell needs to interact with system APIs in several places, for which FFI code with unsafe blocks may be necessary. In some cases this can be handled by safe API wrapper crates but in some cases we may choose to directly do those calls.
|
||||
If you do so you need to document the system behavior on top of the Rust memory model guarantees that you uphold. This means documenting whether using a particular system call is safe to use in a particular context and all failure cases are properly recovered.
|
||||
##### Implementing self-contained data structures
|
||||
Another motivation for reaching to `unsafe` code might be to try to implement a particular data structure that is not expressible on safe `std` library APIs. Doing so in the Nushell code base would have to clear a high bar for need based on profiling results. Also you should first do a survey of the [crate ecosystem](https://crates.io) that there doesn't exist a usable well vetted crate that already provides safe APIs to the desired datastructure.
|
||||
##### Make things go faster by removing checks
|
||||
This is probably a bad idea if you feel tempted to do so. Don't
|
||||
#### Macros
|
||||
Another advanced feature people feel tempted to use to work around perceived limitations of Rusts syntax and we are not particularly fans of are custom macros.
|
||||
They have clear downsides not only in terms of readability if they locally introduce a different syntax. Most tooling apart from the compiler will struggle more with them. This limits for example consistent automatic formatting or automated refactors with `rust-analyzer`.
|
||||
That you can fluently read `macro_rules!` is less likely than regular code. This can lead people to introduce funky behavior when using a macro. Be it because a macro is not following proper hygiene rules or because it introduces excessive work at compile time.
|
||||
|
||||
So we generally discourage the addition of macros. In a lot of cases your macro may start do something that can be expressed with functions or generics in a much more reusable fashion.
|
||||
The only exceptions we may allow need to demonstrate that the macro can fix something that is otherwise extremely unreadable, error-prone, or consistently worse at compile time.
|
||||
### Things we want to get better at
|
||||
These are things we did pretty liberally to get Nushell off the ground, that make things harder for a high quality stable product. You may run across them but shouldn't take them as an endorsed example.
|
||||
#### Liberal use of third-party dependencies
|
||||
The amazing variety of crates on [crates.io](https://crates.io) allowed us to quickly get Nushell into a feature rich state but it left us with a bunch of baggage to clean up.
|
||||
Each dependency introduces a compile time cost and duplicated code can add to the overall binary size. Also vetting more for correct and secure implementations takes unreasonably more time as this is also a continuous process of reacting to updates or potential vulnerabilities.
|
||||
|
||||
Thus we only want to accept dependencies that are essential and well tested implementations of a particular requirement of Nushells codebase.
|
||||
Also as a project for the move to 1.0 we will try to unify among a set of dependencies if they possibly implement similar things in an area. We don't need three different crates with potentially perfect fit for three problems but rather one reliable crate with a maximized overlap between what it provides and what we need.
|
||||
We will favor crates that are well tested and used and promise to be more stable and still frequently maintained.
|
||||
#### Deeply nested code
|
||||
As Nushell uses a lot of enums in its internal data representation there are a lot of `match` expressions. Combined with the need to handle a lot of edge cases and be defensive about any errors this has led to some absolutely hard to read deeply nested code (e.g. in the parser but also in the implementation of several commands).
|
||||
This can be observed both as a "rightward drift" where the main part of the code is found after many levels of indentations or by long function bodies with several layers of branching with seemingly repeated branching inside the higher branch level.
|
||||
This can also be exacerbated by "quick" bugfixes/enhancements that may just try to add a special case to catch a previously unexpected condition. The likelihood of introducing a bug in a sea of code duplication is high.
|
||||
To combat this, consider using the early-`return` pattern to reject invalid data early in one place instead of building a tree through Rust's expression constructs with a lot of duplicated paths. Unpacking data into a type that expresses that the necessary things already have been checked and using functions to properly deal with separate and common behavior can also help.
|
||||
|
||||
## License
|
||||
|
||||
We use the [MIT License](https://github.com/nushell/nushell/blob/main/LICENSE) in all of our Nushell projects. If you are including or referencing a crate that uses the [GPL License](https://www.gnu.org/licenses/gpl-3.0.en.html#license-text) unfortunately we will not be able to accept your PR.
|
||||
|
1507
Cargo.lock
generated
1507
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
50
Cargo.toml
50
Cargo.toml
@ -10,8 +10,8 @@ homepage = "https://www.nushell.sh"
|
||||
license = "MIT"
|
||||
name = "nu"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
rust-version = "1.60"
|
||||
version = "0.87.0"
|
||||
rust-version = "1.72.1"
|
||||
version = "0.88.2"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -47,29 +47,29 @@ members = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.87.0" }
|
||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.87.0" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.87.0" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.87.0" }
|
||||
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.87.0", features = ["dataframe"], optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.87.0", optional = true }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.87.0" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.87.0" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.87.0" }
|
||||
nu-json = { path = "./crates/nu-json", version = "0.87.0" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.87.0" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.87.0" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.87.0" }
|
||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.87.0" }
|
||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.87.0" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.87.0" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.87.0" }
|
||||
nu-table = { path = "./crates/nu-table", version = "0.87.0" }
|
||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.87.0" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.87.0" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.87.0" }
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.88.2" }
|
||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.88.2" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.88.2" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.88.2" }
|
||||
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.88.2", features = ["dataframe"], optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.88.2", optional = true }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.88.2" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.88.2" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.88.2" }
|
||||
nu-json = { path = "./crates/nu-json", version = "0.88.2" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.88.2" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.88.2" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.88.2" }
|
||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.88.2" }
|
||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.88.2" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.88.2" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.88.2" }
|
||||
nu-table = { path = "./crates/nu-table", version = "0.88.2" }
|
||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.88.2" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.88.2" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.88.2" }
|
||||
nu-ansi-term = "0.49.0"
|
||||
reedline = { version = "0.26.0", features = ["bashisms", "sqlite"] }
|
||||
reedline = { version = "0.27.0", features = ["bashisms", "sqlite"] }
|
||||
|
||||
crossterm = "0.27"
|
||||
ctrlc = "3.4"
|
||||
@ -97,7 +97,7 @@ nix = { version = "0.27", default-features = false, features = [
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.87.0" }
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.88.2" }
|
||||
assert_cmd = "2.0"
|
||||
criterion = "0.5"
|
||||
pretty_assertions = "1.4"
|
||||
|
@ -54,7 +54,7 @@ Detailed installation instructions can be found in the [installation chapter of
|
||||
|
||||
[](https://repology.org/project/nushell/versions)
|
||||
|
||||
For details about which platforms the Nushell team actively supports, see [our platform support policy](PLATFORM_SUPPORT.md).
|
||||
For details about which platforms the Nushell team actively supports, see [our platform support policy](devdocs/PLATFORM_SUPPORT.md).
|
||||
|
||||
## Configuration
|
||||
|
||||
@ -199,7 +199,7 @@ topics that have been presented.
|
||||
|
||||
Nu adheres closely to a set of goals that make up its design philosophy. As features are added, they are checked against these goals.
|
||||
|
||||
- First and foremost, Nu is cross-platform. Commands and techniques should work across platforms and Nu has [first-class support for Windows, macOS, and Linux](PLATFORM_SUPPORT.md).
|
||||
- First and foremost, Nu is cross-platform. Commands and techniques should work across platforms and Nu has [first-class support for Windows, macOS, and Linux](devdocs/PLATFORM_SUPPORT.md).
|
||||
|
||||
- Nu ensures compatibility with existing platform-specific executables.
|
||||
|
||||
|
@ -4,10 +4,35 @@ use nu_parser::parse;
|
||||
use nu_plugin::{EncodingType, PluginResponse};
|
||||
use nu_protocol::{engine::EngineState, PipelineData, Span, Value};
|
||||
use nu_utils::{get_default_config, get_default_env};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn load_bench_commands() -> EngineState {
|
||||
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
|
||||
}
|
||||
|
||||
fn canonicalize_path(engine_state: &EngineState, path: &Path) -> PathBuf {
|
||||
let cwd = engine_state.current_work_dir();
|
||||
|
||||
if path.exists() {
|
||||
match nu_path::canonicalize_with(path, cwd) {
|
||||
Ok(canon_path) => canon_path,
|
||||
Err(_) => path.to_owned(),
|
||||
}
|
||||
} else {
|
||||
path.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_home_path(engine_state: &EngineState) -> PathBuf {
|
||||
let home_path = if let Some(path) = nu_path::home_dir() {
|
||||
let canon_home_path = canonicalize_path(engine_state, &path);
|
||||
canon_home_path
|
||||
} else {
|
||||
std::path::PathBuf::new()
|
||||
};
|
||||
home_path
|
||||
}
|
||||
|
||||
// FIXME: All benchmarks live in this 1 file to speed up build times when benchmarking.
|
||||
// When the *_benchmarks functions were in different files, `cargo bench` would build
|
||||
// an executable for every single one - incredibly slowly. Would be nice to figure out
|
||||
@ -15,10 +40,12 @@ fn load_bench_commands() -> EngineState {
|
||||
|
||||
fn parser_benchmarks(c: &mut Criterion) {
|
||||
let mut engine_state = load_bench_commands();
|
||||
// parsing config.nu breaks without PWD set
|
||||
let home_path = get_home_path(&engine_state);
|
||||
|
||||
// parsing config.nu breaks without PWD set, so set a valid path
|
||||
engine_state.add_env_var(
|
||||
"PWD".into(),
|
||||
Value::string("/some/dir".to_string(), Span::test_data()),
|
||||
Value::string(home_path.to_string_lossy(), Span::test_data()),
|
||||
);
|
||||
|
||||
let default_env = get_default_env().as_bytes();
|
||||
@ -41,7 +68,6 @@ fn parser_benchmarks(c: &mut Criterion) {
|
||||
|
||||
c.bench_function("eval default_env.nu", |b| {
|
||||
b.iter(|| {
|
||||
let mut engine_state = load_bench_commands();
|
||||
let mut stack = nu_protocol::engine::Stack::new();
|
||||
eval_source(
|
||||
&mut engine_state,
|
||||
@ -56,12 +82,6 @@ fn parser_benchmarks(c: &mut Criterion) {
|
||||
|
||||
c.bench_function("eval default_config.nu", |b| {
|
||||
b.iter(|| {
|
||||
let mut engine_state = load_bench_commands();
|
||||
// parsing config.nu breaks without PWD set
|
||||
engine_state.add_env_var(
|
||||
"PWD".into(),
|
||||
Value::string("/some/dir".to_string(), Span::test_data()),
|
||||
);
|
||||
let mut stack = nu_protocol::engine::Stack::new();
|
||||
eval_source(
|
||||
&mut engine_state,
|
||||
@ -76,9 +96,17 @@ fn parser_benchmarks(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn eval_benchmarks(c: &mut Criterion) {
|
||||
let mut engine_state = load_bench_commands();
|
||||
let home_path = get_home_path(&engine_state);
|
||||
|
||||
// parsing config.nu breaks without PWD set, so set a valid path
|
||||
engine_state.add_env_var(
|
||||
"PWD".into(),
|
||||
Value::string(home_path.to_string_lossy(), Span::test_data()),
|
||||
);
|
||||
|
||||
c.bench_function("eval default_env.nu", |b| {
|
||||
b.iter(|| {
|
||||
let mut engine_state = load_bench_commands();
|
||||
let mut stack = nu_protocol::engine::Stack::new();
|
||||
eval_source(
|
||||
&mut engine_state,
|
||||
@ -93,12 +121,6 @@ fn eval_benchmarks(c: &mut Criterion) {
|
||||
|
||||
c.bench_function("eval default_config.nu", |b| {
|
||||
b.iter(|| {
|
||||
let mut engine_state = load_bench_commands();
|
||||
// parsing config.nu breaks without PWD set
|
||||
engine_state.add_env_var(
|
||||
"PWD".into(),
|
||||
Value::string("/some/dir".to_string(), Span::test_data()),
|
||||
);
|
||||
let mut stack = nu_protocol::engine::Stack::new();
|
||||
eval_source(
|
||||
&mut engine_state,
|
||||
|
@ -5,27 +5,27 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.87.0"
|
||||
version = "0.88.2"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.87.0" }
|
||||
nu-command = { path = "../nu-command", version = "0.87.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.87.0" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.88.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.88.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.88.2" }
|
||||
rstest = { version = "0.18.1", default-features = false }
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.87.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.87.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.87.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.87.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.87.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.87.0" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.87.0" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.88.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.88.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.88.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.88.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.88.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.88.2" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.88.2" }
|
||||
nu-ansi-term = "0.49.0"
|
||||
reedline = { version = "0.26.0", features = ["bashisms", "sqlite"] }
|
||||
reedline = { version = "0.27.0", features = ["bashisms", "sqlite"] }
|
||||
|
||||
chrono = { default-features = false, features = ["std"], version = "0.4" }
|
||||
crossterm = "0.27"
|
||||
@ -39,7 +39,8 @@ percent-encoding = "2"
|
||||
pathdiff = "0.2"
|
||||
sysinfo = "0.29"
|
||||
unicode-segmentation = "1.10"
|
||||
uuid = { version = "1.5.0", features = ["v4"] }
|
||||
uuid = { version = "1.6.0", features = ["v4"] }
|
||||
which = "5.0.0"
|
||||
|
||||
[features]
|
||||
plugin = []
|
||||
|
@ -34,7 +34,7 @@ impl Command for History {
|
||||
"Show long listing of entries for sqlite history",
|
||||
Some('l'),
|
||||
)
|
||||
.category(Category::Misc)
|
||||
.category(Category::History)
|
||||
}
|
||||
|
||||
fn run(
|
||||
@ -107,7 +107,7 @@ impl Command for History {
|
||||
)
|
||||
})
|
||||
})
|
||||
.ok_or(ShellError::FileNotFound(head))?
|
||||
.ok_or(ShellError::FileNotFound { span: head })?
|
||||
.into_pipeline_data(ctrlc)),
|
||||
HistoryFileFormat::Sqlite => Ok(history_reader
|
||||
.and_then(|h| {
|
||||
@ -119,12 +119,12 @@ impl Command for History {
|
||||
create_history_record(idx, entry, long, head)
|
||||
})
|
||||
})
|
||||
.ok_or(ShellError::FileNotFound(head))?
|
||||
.ok_or(ShellError::FileNotFound { span: head })?
|
||||
.into_pipeline_data(ctrlc)),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::FileNotFound(head))
|
||||
Err(ShellError::FileNotFound { span: head })
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ impl Command for HistorySession {
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("history session")
|
||||
.category(Category::Misc)
|
||||
.category(Category::History)
|
||||
.input_output_types(vec![(Type::Nothing, Type::Int)])
|
||||
}
|
||||
|
5
crates/nu-cli/src/commands/history/mod.rs
Normal file
5
crates/nu-cli/src/commands/history/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod history_;
|
||||
mod history_session;
|
||||
|
||||
pub use history_::History;
|
||||
pub use history_session::HistorySession;
|
@ -45,13 +45,13 @@ impl Command for KeybindingsListen {
|
||||
Ok(v) => Ok(v.into_pipeline_data()),
|
||||
Err(e) => {
|
||||
terminal::disable_raw_mode()?;
|
||||
Err(ShellError::GenericError(
|
||||
"Error with input".to_string(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
))
|
||||
Err(ShellError::GenericError {
|
||||
error: "Error with input".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
mod commandline;
|
||||
mod default_context;
|
||||
mod history;
|
||||
mod history_session;
|
||||
mod keybindings;
|
||||
mod keybindings_default;
|
||||
mod keybindings_list;
|
||||
mod keybindings_listen;
|
||||
|
||||
pub use commandline::Commandline;
|
||||
pub use history::History;
|
||||
pub use history_session::HistorySession;
|
||||
pub use history::{History, HistorySession};
|
||||
pub use keybindings::Keybindings;
|
||||
pub use keybindings_default::KeybindingsDefault;
|
||||
pub use keybindings_list::KeybindingsList;
|
||||
|
@ -67,7 +67,7 @@ impl NuCompleter {
|
||||
let mut callee_stack = stack.gather_captures(&self.engine_state, &block.captures);
|
||||
|
||||
// Line
|
||||
if let Some(pos_arg) = block.signature.required_positional.get(0) {
|
||||
if let Some(pos_arg) = block.signature.required_positional.first() {
|
||||
if let Some(var_id) = pos_arg.var_id {
|
||||
callee_stack.add_var(
|
||||
var_id,
|
||||
@ -122,11 +122,13 @@ impl NuCompleter {
|
||||
for pipeline_element in pipeline.elements {
|
||||
match pipeline_element {
|
||||
PipelineElement::Expression(_, expr)
|
||||
| PipelineElement::Redirection(_, _, expr)
|
||||
| PipelineElement::Redirection(_, _, expr, _)
|
||||
| PipelineElement::And(_, expr)
|
||||
| PipelineElement::Or(_, expr)
|
||||
| PipelineElement::SameTargetRedirection { cmd: (_, expr), .. }
|
||||
| PipelineElement::SeparateRedirection { out: (_, expr), .. } => {
|
||||
| PipelineElement::SeparateRedirection {
|
||||
out: (_, expr, _), ..
|
||||
} => {
|
||||
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
|
||||
let mut spans: Vec<String> = vec![];
|
||||
|
||||
@ -141,18 +143,24 @@ impl NuCompleter {
|
||||
let current_span = working_set.get_span_contents(flat.0).to_vec();
|
||||
let current_span_str = String::from_utf8_lossy(¤t_span);
|
||||
|
||||
let is_last_span = pos >= flat.0.start && pos < flat.0.end;
|
||||
|
||||
// Skip the last 'a' as span item
|
||||
if flat_idx == flattened.len() - 1 {
|
||||
let mut chars = current_span_str.chars();
|
||||
chars.next_back();
|
||||
let current_span_str = chars.as_str().to_owned();
|
||||
spans.push(current_span_str.to_string());
|
||||
if is_last_span {
|
||||
let offset = pos - flat.0.start;
|
||||
if offset == 0 {
|
||||
spans.push(String::new())
|
||||
} else {
|
||||
let mut current_span_str = current_span_str.to_string();
|
||||
current_span_str.remove(offset);
|
||||
spans.push(current_span_str);
|
||||
}
|
||||
} else {
|
||||
spans.push(current_span_str.to_string());
|
||||
}
|
||||
|
||||
// Complete based on the last span
|
||||
if pos >= flat.0.start && pos < flat.0.end {
|
||||
if is_last_span {
|
||||
// Context variables
|
||||
let most_left_var =
|
||||
most_left_variable(flat_idx, &working_set, flattened.clone());
|
||||
|
@ -35,10 +35,10 @@ pub fn evaluate_file(
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::FileNotFoundCustom(
|
||||
format!("Could not access file '{}': {:?}", path, e.to_string()),
|
||||
Span::unknown(),
|
||||
),
|
||||
&ShellError::FileNotFoundCustom {
|
||||
msg: format!("Could not access file '{}': {:?}", path, e.to_string()),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
std::process::exit(1);
|
||||
});
|
||||
@ -47,13 +47,13 @@ pub fn evaluate_file(
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::NonUtf8Custom(
|
||||
format!(
|
||||
&ShellError::NonUtf8Custom {
|
||||
msg: format!(
|
||||
"Input file name '{}' is not valid UTF8",
|
||||
file_path.to_string_lossy()
|
||||
),
|
||||
Span::unknown(),
|
||||
),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
std::process::exit(1);
|
||||
});
|
||||
@ -64,14 +64,14 @@ pub fn evaluate_file(
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::FileNotFoundCustom(
|
||||
format!(
|
||||
&ShellError::FileNotFoundCustom {
|
||||
msg: format!(
|
||||
"Could not read file '{}': {:?}",
|
||||
file_path_str,
|
||||
e.to_string()
|
||||
),
|
||||
Span::unknown(),
|
||||
),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
std::process::exit(1);
|
||||
});
|
||||
@ -82,10 +82,10 @@ pub fn evaluate_file(
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::FileNotFoundCustom(
|
||||
format!("The file path '{file_path_str}' does not have a parent"),
|
||||
Span::unknown(),
|
||||
),
|
||||
&ShellError::FileNotFoundCustom {
|
||||
msg: format!("The file path '{file_path_str}' does not have a parent"),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
std::process::exit(1);
|
||||
});
|
||||
@ -98,6 +98,10 @@ pub fn evaluate_file(
|
||||
"CURRENT_FILE".to_string(),
|
||||
Value::string(file_path.to_string_lossy(), Span::unknown()),
|
||||
);
|
||||
stack.add_env_var(
|
||||
"PROCESS_PATH".to_string(),
|
||||
Value::string(path, Span::unknown()),
|
||||
);
|
||||
|
||||
let source_filename = file_path
|
||||
.file_name()
|
||||
@ -135,7 +139,7 @@ pub fn evaluate_file(
|
||||
false,
|
||||
);
|
||||
let pipeline_data = match pipeline_data {
|
||||
Err(ShellError::Return(_, _)) => {
|
||||
Err(ShellError::Return { .. }) => {
|
||||
// allows early exists before `main` is run.
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -139,18 +139,18 @@ fn add_menu(
|
||||
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
|
||||
"list" => add_list_menu(line_editor, menu, engine_state, stack, config),
|
||||
"description" => add_description_menu(line_editor, menu, engine_state, stack, config),
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"columnar, list or description".to_string(),
|
||||
menu.menu_type.into_abbreviated_string(config),
|
||||
menu.menu_type.span(),
|
||||
)),
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "columnar, list or description".to_string(),
|
||||
value: menu.menu_type.into_abbreviated_string(config),
|
||||
span: menu.menu_type.span(),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::UnsupportedConfigValue(
|
||||
"only record type".to_string(),
|
||||
menu.menu_type.into_abbreviated_string(config),
|
||||
menu.menu_type.span(),
|
||||
))
|
||||
Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "only record type".to_string(),
|
||||
value: menu.menu_type.into_abbreviated_string(config),
|
||||
span: menu.menu_type.span(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,11 +261,11 @@ pub(crate) fn add_columnar_menu(
|
||||
completer: Box::new(menu_completer),
|
||||
}))
|
||||
}
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"block or omitted value".to_string(),
|
||||
menu.source.into_abbreviated_string(config),
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "block or omitted value".to_string(),
|
||||
value: menu.source.into_abbreviated_string(config),
|
||||
span,
|
||||
)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,11 +343,11 @@ pub(crate) fn add_list_menu(
|
||||
completer: Box::new(menu_completer),
|
||||
}))
|
||||
}
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"block or omitted value".to_string(),
|
||||
menu.source.into_abbreviated_string(config),
|
||||
menu.source.span(),
|
||||
)),
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "block or omitted value".to_string(),
|
||||
value: menu.source.into_abbreviated_string(config),
|
||||
span: menu.source.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,11 +461,11 @@ pub(crate) fn add_description_menu(
|
||||
completer: Box::new(menu_completer),
|
||||
}))
|
||||
}
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"closure or omitted value".to_string(),
|
||||
menu.source.into_abbreviated_string(config),
|
||||
menu.source.span(),
|
||||
)),
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "closure or omitted value".to_string(),
|
||||
value: menu.source.into_abbreviated_string(config),
|
||||
span: menu.source.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -580,11 +580,11 @@ fn add_keybinding(
|
||||
"emacs" => add_parsed_keybinding(emacs_keybindings, keybinding, config),
|
||||
"vi_insert" => add_parsed_keybinding(insert_keybindings, keybinding, config),
|
||||
"vi_normal" => add_parsed_keybinding(normal_keybindings, keybinding, config),
|
||||
m => Err(ShellError::UnsupportedConfigValue(
|
||||
"emacs, vi_insert or vi_normal".to_string(),
|
||||
m.to_string(),
|
||||
m => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "emacs, vi_insert or vi_normal".to_string(),
|
||||
value: m.to_string(),
|
||||
span,
|
||||
)),
|
||||
}),
|
||||
},
|
||||
Value::List { vals, .. } => {
|
||||
for inner_mode in vals {
|
||||
@ -600,11 +600,11 @@ fn add_keybinding(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
v => Err(ShellError::UnsupportedConfigValue(
|
||||
"string or list of strings".to_string(),
|
||||
v.into_abbreviated_string(config),
|
||||
v.span(),
|
||||
)),
|
||||
v => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "string or list of strings".to_string(),
|
||||
value: v.into_abbreviated_string(config),
|
||||
span: v.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -630,11 +630,11 @@ fn add_parsed_keybinding(
|
||||
KeyModifiers::CONTROL | KeyModifiers::ALT | KeyModifiers::SHIFT
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"CONTROL, SHIFT, ALT or NONE".to_string(),
|
||||
keybinding.modifier.into_abbreviated_string(config),
|
||||
keybinding.modifier.span(),
|
||||
))
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "CONTROL, SHIFT, ALT or NONE".to_string(),
|
||||
value: keybinding.modifier.into_abbreviated_string(config),
|
||||
span: keybinding.modifier.span(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@ -654,11 +654,11 @@ fn add_parsed_keybinding(
|
||||
let char = if let (Some(char), None) = (pos1, pos2) {
|
||||
char
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"char_<CHAR: unicode codepoint>".to_string(),
|
||||
c.to_string(),
|
||||
keybinding.keycode.span(),
|
||||
));
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "char_<CHAR: unicode codepoint>".to_string(),
|
||||
value: c.to_string(),
|
||||
span: keybinding.keycode.span(),
|
||||
});
|
||||
};
|
||||
|
||||
KeyCode::Char(char)
|
||||
@ -681,21 +681,21 @@ fn add_parsed_keybinding(
|
||||
.parse()
|
||||
.ok()
|
||||
.filter(|num| matches!(num, 1..=20))
|
||||
.ok_or(ShellError::UnsupportedConfigValue(
|
||||
"(f1|f2|...|f20)".to_string(),
|
||||
format!("unknown function key: {c}"),
|
||||
keybinding.keycode.span(),
|
||||
))?;
|
||||
.ok_or(ShellError::UnsupportedConfigValue {
|
||||
expected: "(f1|f2|...|f20)".to_string(),
|
||||
value: format!("unknown function key: {c}"),
|
||||
span: keybinding.keycode.span(),
|
||||
})?;
|
||||
KeyCode::F(fn_num)
|
||||
}
|
||||
"null" => KeyCode::Null,
|
||||
"esc" | "escape" => KeyCode::Esc,
|
||||
_ => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"crossterm KeyCode".to_string(),
|
||||
keybinding.keycode.into_abbreviated_string(config),
|
||||
keybinding.keycode.span(),
|
||||
))
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "crossterm KeyCode".to_string(),
|
||||
value: keybinding.keycode.into_abbreviated_string(config),
|
||||
span: keybinding.keycode.span(),
|
||||
})
|
||||
}
|
||||
};
|
||||
if let Some(event) = parse_event(&keybinding.event, config)? {
|
||||
@ -719,7 +719,10 @@ impl<'config> EventType<'config> {
|
||||
.map(Self::Send)
|
||||
.or_else(|_| extract_value("edit", record, span).map(Self::Edit))
|
||||
.or_else(|_| extract_value("until", record, span).map(Self::Until))
|
||||
.map_err(|_| ShellError::MissingConfigValue("send, edit or until".to_string(), span))
|
||||
.map_err(|_| ShellError::MissingConfigValue {
|
||||
missing_value: "send, edit or until".to_string(),
|
||||
span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,11 +752,11 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
|
||||
.iter()
|
||||
.map(|value| match parse_event(value, config) {
|
||||
Ok(inner) => match inner {
|
||||
None => Err(ShellError::UnsupportedConfigValue(
|
||||
"List containing valid events".to_string(),
|
||||
"Nothing value (null)".to_string(),
|
||||
value.span(),
|
||||
)),
|
||||
None => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "List containing valid events".to_string(),
|
||||
value: "Nothing value (null)".to_string(),
|
||||
span: value.span(),
|
||||
}),
|
||||
Some(event) => Ok(event),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
@ -762,11 +765,11 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
|
||||
|
||||
Ok(Some(ReedlineEvent::UntilFound(events)))
|
||||
}
|
||||
v => Err(ShellError::UnsupportedConfigValue(
|
||||
"list of events".to_string(),
|
||||
v.into_abbreviated_string(config),
|
||||
v.span(),
|
||||
)),
|
||||
v => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "list of events".to_string(),
|
||||
value: v.into_abbreviated_string(config),
|
||||
span: v.span(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
Value::List { vals, .. } => {
|
||||
@ -774,11 +777,11 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
|
||||
.iter()
|
||||
.map(|value| match parse_event(value, config) {
|
||||
Ok(inner) => match inner {
|
||||
None => Err(ShellError::UnsupportedConfigValue(
|
||||
"List containing valid events".to_string(),
|
||||
"Nothing value (null)".to_string(),
|
||||
value.span(),
|
||||
)),
|
||||
None => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "List containing valid events".to_string(),
|
||||
value: "Nothing value (null)".to_string(),
|
||||
span: value.span(),
|
||||
}),
|
||||
Some(event) => Ok(event),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
@ -788,11 +791,11 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
|
||||
Ok(Some(ReedlineEvent::Multiple(events)))
|
||||
}
|
||||
Value::Nothing { .. } => Ok(None),
|
||||
v => Err(ShellError::UnsupportedConfigValue(
|
||||
"record or list of records, null to unbind key".to_string(),
|
||||
v.into_abbreviated_string(config),
|
||||
v.span(),
|
||||
)),
|
||||
v => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "record or list of records, null to unbind key".to_string(),
|
||||
value: v.into_abbreviated_string(config),
|
||||
span: v.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -840,11 +843,11 @@ fn event_from_record(
|
||||
ReedlineEvent::ExecuteHostCommand(cmd.into_string("", config))
|
||||
}
|
||||
v => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"Reedline event".to_string(),
|
||||
v.to_string(),
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "Reedline event".to_string(),
|
||||
value: v.to_string(),
|
||||
span,
|
||||
))
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@ -954,11 +957,11 @@ fn edit_from_record(
|
||||
}
|
||||
"complete" => EditCommand::Complete,
|
||||
e => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"reedline EditCommand".to_string(),
|
||||
e.to_string(),
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "reedline EditCommand".to_string(),
|
||||
value: e.to_string(),
|
||||
span,
|
||||
))
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@ -971,7 +974,10 @@ fn extract_char(value: &Value, config: &Config) -> Result<char, ShellError> {
|
||||
.into_string("", config)
|
||||
.chars()
|
||||
.next()
|
||||
.ok_or_else(|| ShellError::MissingConfigValue("char to insert".to_string(), span))
|
||||
.ok_or_else(|| ShellError::MissingConfigValue {
|
||||
missing_value: "char to insert".to_string(),
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -1101,6 +1107,6 @@ mod test {
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_record(&event, span);
|
||||
assert!(matches!(b, Err(ShellError::MissingConfigValue(_, _))));
|
||||
assert!(matches!(b, Err(ShellError::MissingConfigValue { .. })));
|
||||
}
|
||||
}
|
||||
|
@ -502,10 +502,10 @@ pub fn evaluate_repl(
|
||||
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::DirectoryNotFound(
|
||||
tokens.0[0].span,
|
||||
path.to_string_lossy().to_string(),
|
||||
),
|
||||
&ShellError::DirectoryNotFound {
|
||||
dir: path.to_string_lossy().to_string(),
|
||||
span: tokens.0[0].span,
|
||||
},
|
||||
);
|
||||
}
|
||||
let path = nu_path::canonicalize_with(path, &cwd)
|
||||
@ -773,23 +773,21 @@ pub fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) ->
|
||||
}
|
||||
|
||||
fn run_ansi_sequence(seq: &str) -> Result<(), ShellError> {
|
||||
io::stdout().write_all(seq.as_bytes()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error writing ansi sequence".into(),
|
||||
e.to_string(),
|
||||
Some(Span::unknown()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
io::stdout().flush().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error flushing stdio".into(),
|
||||
e.to_string(),
|
||||
Some(Span::unknown()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
io::stdout()
|
||||
.write_all(seq.as_bytes())
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error writing ansi sequence".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(Span::unknown()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
io::stdout().flush().map_err(|e| ShellError::GenericError {
|
||||
error: "Error flushing stdio".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(Span::unknown()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use log::trace;
|
||||
use nu_ansi_term::Style;
|
||||
use nu_color_config::{get_matching_brackets_style, get_shape_color};
|
||||
use nu_parser::{flatten_block, parse, FlatShape};
|
||||
use nu_protocol::ast::{Argument, Block, Expr, Expression, PipelineElement};
|
||||
use nu_protocol::ast::{Argument, Block, Expr, Expression, PipelineElement, RecordItem};
|
||||
use nu_protocol::engine::{EngineState, StateWorkingSet};
|
||||
use nu_protocol::{Config, Span};
|
||||
use reedline::{Highlighter, StyledText};
|
||||
@ -17,10 +17,27 @@ impl Highlighter for NuHighlighter {
|
||||
fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
|
||||
trace!("highlighting: {}", line);
|
||||
|
||||
let highlight_resolved_externals =
|
||||
self.engine_state.get_config().highlight_resolved_externals;
|
||||
let mut working_set = StateWorkingSet::new(&self.engine_state);
|
||||
let block = parse(&mut working_set, None, line.as_bytes(), false);
|
||||
let (shapes, global_span_offset) = {
|
||||
let shapes = flatten_block(&working_set, &block);
|
||||
let mut shapes = flatten_block(&working_set, &block);
|
||||
// Highlighting externals has a config point because of concerns that using which to resolve
|
||||
// externals may slow down things too much.
|
||||
if highlight_resolved_externals {
|
||||
for (span, shape) in shapes.iter_mut() {
|
||||
if *shape == FlatShape::External {
|
||||
let str_contents =
|
||||
working_set.get_span_contents(Span::new(span.start, span.end));
|
||||
|
||||
let str_word = String::from_utf8_lossy(str_contents).to_string();
|
||||
if which::which(str_word).ok().is_some() {
|
||||
*shape = FlatShape::ExternalResolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(shapes, self.engine_state.next_span_start())
|
||||
};
|
||||
|
||||
@ -91,6 +108,7 @@ impl Highlighter for NuHighlighter {
|
||||
FlatShape::InternalCall(_) => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::External => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::ExternalArg => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::ExternalResolved => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::Keyword => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::Literal => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::Operator => add_colored_token(&shape.1, next_token),
|
||||
@ -234,11 +252,11 @@ fn find_matching_block_end_in_block(
|
||||
for e in &p.elements {
|
||||
match e {
|
||||
PipelineElement::Expression(_, e)
|
||||
| PipelineElement::Redirection(_, _, e)
|
||||
| PipelineElement::Redirection(_, _, e, _)
|
||||
| PipelineElement::And(_, e)
|
||||
| PipelineElement::Or(_, e)
|
||||
| PipelineElement::SameTargetRedirection { cmd: (_, e), .. }
|
||||
| PipelineElement::SeparateRedirection { out: (_, e), .. } => {
|
||||
| PipelineElement::SeparateRedirection { out: (_, e, _), .. } => {
|
||||
if e.span.contains(global_cursor_offset) {
|
||||
if let Some(pos) = find_matching_block_end_in_expr(
|
||||
line,
|
||||
@ -315,6 +333,7 @@ fn find_matching_block_end_in_expr(
|
||||
Expr::MatchBlock(_) => None,
|
||||
Expr::Nothing => None,
|
||||
Expr::Garbage => None,
|
||||
Expr::Spread(_) => None,
|
||||
|
||||
Expr::Table(hdr, rows) => {
|
||||
if expr_last == global_cursor_offset {
|
||||
@ -346,9 +365,16 @@ fn find_matching_block_end_in_expr(
|
||||
Some(expr_last)
|
||||
} else {
|
||||
// cursor is inside record
|
||||
for (k, v) in exprs {
|
||||
find_in_expr_or_continue!(k);
|
||||
find_in_expr_or_continue!(v);
|
||||
for expr in exprs {
|
||||
match expr {
|
||||
RecordItem::Pair(k, v) => {
|
||||
find_in_expr_or_continue!(k);
|
||||
find_in_expr_or_continue!(v);
|
||||
}
|
||||
RecordItem::Spread(_, record) => {
|
||||
find_in_expr_or_continue!(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -43,13 +43,13 @@ fn gather_env_vars(
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::GenericError(
|
||||
format!("Environment variable was not captured: {env_str}"),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(msg.into()),
|
||||
Vec::new(),
|
||||
),
|
||||
&ShellError::GenericError {
|
||||
error: format!("Environment variable was not captured: {env_str}"),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(msg.into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -75,15 +75,15 @@ fn gather_env_vars(
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::GenericError(
|
||||
"Current directory is not a valid utf-8 path".to_string(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(format!(
|
||||
&ShellError::GenericError {
|
||||
error: "Current directory is not a valid utf-8 path".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(format!(
|
||||
"Retrieving current directory failed: {init_cwd:?} not a valid utf-8 path"
|
||||
)),
|
||||
Vec::new(),
|
||||
),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,7 @@ fn gather_env_vars(
|
||||
let name = if let Some(Token {
|
||||
contents: TokenContents::Item,
|
||||
span,
|
||||
}) = parts.get(0)
|
||||
}) = parts.first()
|
||||
{
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
let bytes = working_set.get_span_contents(*span);
|
||||
|
@ -59,6 +59,29 @@ fn extern_completer() -> NuCompleter {
|
||||
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
fn custom_completer() -> NuCompleter {
|
||||
// Create a new engine
|
||||
let (dir, _, mut engine, mut stack) = new_engine();
|
||||
|
||||
// Add record value as example
|
||||
let record = r#"
|
||||
let external_completer = {|spans|
|
||||
$spans
|
||||
}
|
||||
|
||||
$env.config.completions.external = {
|
||||
enable: true
|
||||
max_results: 100
|
||||
completer: $external_completer
|
||||
}
|
||||
"#;
|
||||
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||
|
||||
// Instantiate a new completer
|
||||
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn variables_dollar_sign_with_varialblecompletion() {
|
||||
let (_, _, engine, stack) = new_engine();
|
||||
@ -122,14 +145,14 @@ fn dotnu_completions() {
|
||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||
|
||||
assert_eq!(1, suggestions.len());
|
||||
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
||||
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
|
||||
|
||||
// Test use completion
|
||||
let completion_str = "use ".to_string();
|
||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||
|
||||
assert_eq!(1, suggestions.len());
|
||||
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
||||
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -141,7 +164,7 @@ fn external_completer_trailing_space() {
|
||||
|
||||
let suggestions = run_external_completion(block, &input);
|
||||
assert_eq!(3, suggestions.len());
|
||||
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
||||
assert_eq!("gh", suggestions.first().unwrap().value);
|
||||
assert_eq!("alias", suggestions.get(1).unwrap().value);
|
||||
assert_eq!("", suggestions.get(2).unwrap().value);
|
||||
}
|
||||
@ -153,7 +176,7 @@ fn external_completer_no_trailing_space() {
|
||||
|
||||
let suggestions = run_external_completion(block, &input);
|
||||
assert_eq!(2, suggestions.len());
|
||||
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
||||
assert_eq!("gh", suggestions.first().unwrap().value);
|
||||
assert_eq!("alias", suggestions.get(1).unwrap().value);
|
||||
}
|
||||
|
||||
@ -164,7 +187,7 @@ fn external_completer_pass_flags() {
|
||||
|
||||
let suggestions = run_external_completion(block, &input);
|
||||
assert_eq!(3, suggestions.len());
|
||||
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
||||
assert_eq!("gh", suggestions.first().unwrap().value);
|
||||
assert_eq!("api", suggestions.get(1).unwrap().value);
|
||||
assert_eq!("--", suggestions.get(2).unwrap().value);
|
||||
}
|
||||
@ -938,6 +961,34 @@ fn extern_complete_flags(mut extern_completer: NuCompleter) {
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_before_word(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar", 8);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "".into()];
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_on_word_left_boundary(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar", 8);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "".into()];
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_next_to_word(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar", 11);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "bar".into()];
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_after_word(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar ", 12);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "bar".into(), "".into()];
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[ignore = "was reverted, still needs fixing"]
|
||||
#[rstest]
|
||||
fn alias_offset_bug_7648() {
|
||||
|
@ -5,21 +5,21 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-base"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
||||
version = "0.87.0"
|
||||
version = "0.88.2"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.87.0" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.87.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.87.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.87.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.87.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.87.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.88.2" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.88.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.88.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.88.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.88.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.88.2" }
|
||||
|
||||
indexmap = "2.1"
|
||||
miette = "5.10.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.87.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.88.2" }
|
||||
rstest = "0.18.2"
|
||||
|
@ -64,12 +64,10 @@ fn arg_glob_opt(
|
||||
// user wasn't referring to a specific thing in filesystem, try to glob it.
|
||||
match glob_with_parent(&pattern.item, options, cwd) {
|
||||
Ok(p) => Ok(p),
|
||||
Err(pat_err) => {
|
||||
Err(ShellError::InvalidGlobPattern(
|
||||
pat_err.msg.into(),
|
||||
pattern.span, // improve specificity
|
||||
))
|
||||
}
|
||||
Err(pat_err) => Err(ShellError::InvalidGlobPattern {
|
||||
msg: pat_err.msg.into(),
|
||||
span: pattern.span,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,11 +90,11 @@ pub fn eval_hook(
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"valid source code".into(),
|
||||
"source code with syntax errors".into(),
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "valid source code".into(),
|
||||
value: "source code with syntax errors".into(),
|
||||
span,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
(output, working_set.render(), vars)
|
||||
@ -164,11 +164,11 @@ pub fn eval_hook(
|
||||
{
|
||||
val
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"boolean output".to_string(),
|
||||
"other PipelineData variant".to_string(),
|
||||
other_span,
|
||||
));
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "boolean output".to_string(),
|
||||
value: "other PipelineData variant".to_string(),
|
||||
span: other_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
@ -176,11 +176,11 @@ pub fn eval_hook(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"block".to_string(),
|
||||
format!("{}", condition.get_type()),
|
||||
other_span,
|
||||
));
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "block".to_string(),
|
||||
value: format!("{}", condition.get_type()),
|
||||
span: other_span,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// always run the hook
|
||||
@ -222,11 +222,11 @@ pub fn eval_hook(
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"valid source code".into(),
|
||||
"source code with syntax errors".into(),
|
||||
source_span,
|
||||
));
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "valid source code".into(),
|
||||
value: "source code with syntax errors".into(),
|
||||
span: source_span,
|
||||
});
|
||||
}
|
||||
|
||||
(output, working_set.render(), vars)
|
||||
@ -277,11 +277,11 @@ pub fn eval_hook(
|
||||
)?;
|
||||
}
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"block or string".to_string(),
|
||||
format!("{}", other.get_type()),
|
||||
source_span,
|
||||
));
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "block or string".to_string(),
|
||||
value: format!("{}", other.get_type()),
|
||||
span: source_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,11 +293,11 @@ pub fn eval_hook(
|
||||
output = run_hook_block(engine_state, stack, val.block_id, input, arguments, span)?;
|
||||
}
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"string, block, record, or list of commands".into(),
|
||||
format!("{}", other.get_type()),
|
||||
other.span(),
|
||||
));
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "string, block, record, or list of commands".into(),
|
||||
value: format!("{}", other.get_type()),
|
||||
span: other.span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,22 +72,22 @@ fn get_editor_commandline(
|
||||
let params = editor_cmd.collect::<Result<_, ShellError>>()?;
|
||||
Ok((editor, params))
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Editor executable is missing".into(),
|
||||
"Set the first element to an executable".into(),
|
||||
Some(value.span()),
|
||||
Some(HELP_MSG.into()),
|
||||
vec![],
|
||||
)),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Editor executable is missing".into(),
|
||||
msg: "Set the first element to an executable".into(),
|
||||
span: Some(value.span()),
|
||||
help: Some(HELP_MSG.into()),
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
Value::String { .. } | Value::List { .. } => Err(ShellError::GenericError(
|
||||
format!("{var_name} should be a non-empty string or list<String>"),
|
||||
"Specify an executable here".into(),
|
||||
Some(value.span()),
|
||||
Some(HELP_MSG.into()),
|
||||
vec![],
|
||||
)),
|
||||
Value::String { .. } | Value::List { .. } => Err(ShellError::GenericError {
|
||||
error: format!("{var_name} should be a non-empty string or list<String>"),
|
||||
msg: "Specify an executable here".into(),
|
||||
span: Some(value.span()),
|
||||
help: Some(HELP_MSG.into()),
|
||||
inner: vec![],
|
||||
}),
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "string or list<string>".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
@ -114,13 +114,14 @@ pub fn get_editor(
|
||||
} else if let Some(value) = env_vars.get("VISUAL") {
|
||||
get_editor_commandline(value, "$env.VISUAL")
|
||||
} else {
|
||||
Err(ShellError::GenericError(
|
||||
"No editor configured".into(),
|
||||
"Please specify one via `$env.config.buffer_editor` or `$env.EDITOR`/`$env.VISUAL`"
|
||||
.into(),
|
||||
Some(span),
|
||||
Some(HELP_MSG.into()),
|
||||
vec![],
|
||||
))
|
||||
Err(ShellError::GenericError {
|
||||
error: "No editor configured".into(),
|
||||
msg:
|
||||
"Please specify one via `$env.config.buffer_editor` or `$env.EDITOR`/`$env.VISUAL`"
|
||||
.into(),
|
||||
span: Some(span),
|
||||
help: Some(HELP_MSG.into()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-dataframe"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-dataframe"
|
||||
version = "0.87.0"
|
||||
version = "0.88.2"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -13,19 +13,22 @@ version = "0.87.0"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.87.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.87.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.87.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.88.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.88.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.88.2" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
chrono = { version = "0.4", features = ["std", "unstable-locales"], default-features = false }
|
||||
chrono-tz = "0.8"
|
||||
fancy-regex = "0.11"
|
||||
fancy-regex = "0.12"
|
||||
indexmap = { version = "2.1" }
|
||||
num = { version = "0.4", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
sqlparser = { version = "0.36.1", optional = true }
|
||||
polars-io = { version = "0.33", features = ["avro"], optional = true }
|
||||
sqlparser = { version = "0.39", optional = true }
|
||||
polars-io = { version = "0.35", features = ["avro"], optional = true }
|
||||
polars-arrow = "0.35"
|
||||
polars-ops = "0.35"
|
||||
polars-plan = "0.35"
|
||||
|
||||
[dependencies.polars]
|
||||
features = [
|
||||
@ -59,12 +62,12 @@ features = [
|
||||
"to_dummies",
|
||||
]
|
||||
optional = true
|
||||
version = "0.33"
|
||||
version = "0.35"
|
||||
|
||||
[features]
|
||||
dataframe = ["num", "polars", "polars-io", "sqlparser"]
|
||||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.87.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.87.0" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.88.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.88.2" }
|
||||
|
@ -68,26 +68,24 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let new_df = col_string
|
||||
.get(0)
|
||||
.ok_or_else(|| {
|
||||
ShellError::GenericError(
|
||||
"Empty names list".into(),
|
||||
"No column names were found".into(),
|
||||
Some(col_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.first()
|
||||
.ok_or_else(|| ShellError::GenericError {
|
||||
error: "Empty names list".into(),
|
||||
msg: "No column names were found".into(),
|
||||
span: Some(col_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.and_then(|col| {
|
||||
df.as_ref().drop(&col.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error dropping column".into(),
|
||||
e.to_string(),
|
||||
Some(col.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
df.as_ref()
|
||||
.drop(&col.item)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error dropping column".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(col.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
})?;
|
||||
|
||||
// If there are more columns in the drop selection list, these
|
||||
@ -96,15 +94,15 @@ fn command(
|
||||
.iter()
|
||||
.skip(1)
|
||||
.try_fold(new_df, |new_df, col| {
|
||||
new_df.drop(&col.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error dropping column".into(),
|
||||
e.to_string(),
|
||||
Some(col.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
new_df
|
||||
.drop(&col.item)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error dropping column".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(col.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -100,14 +100,12 @@ fn command(
|
||||
|
||||
df.as_ref()
|
||||
.unique(subset_slice, keep_strategy, None)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error dropping duplicates".into(),
|
||||
e.to_string(),
|
||||
Some(col_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error dropping duplicates".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(col_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -115,14 +115,12 @@ fn command(
|
||||
|
||||
df.as_ref()
|
||||
.drop_nulls(subset_slice)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error dropping nulls".into(),
|
||||
e.to_string(),
|
||||
Some(col_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error dropping nulls".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(col_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -88,14 +88,12 @@ fn command(
|
||||
|
||||
df.as_ref()
|
||||
.to_dummies(None, drop_first)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error calculating dummies".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The only allowed column types for dummies are String or Int".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error calculating dummies".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The only allowed column types for dummies are String or Int".into()),
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -105,26 +105,22 @@ fn command_eager(
|
||||
))
|
||||
} else {
|
||||
let mask = NuDataFrame::try_from_value(mask_value)?.as_series(mask_span)?;
|
||||
let mask = mask.bool().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to bool".into(),
|
||||
e.to_string(),
|
||||
Some(mask_span),
|
||||
Some("Perhaps you want to use a series with booleans as mask".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
let mask = mask.bool().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to bool".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(mask_span),
|
||||
help: Some("Perhaps you want to use a series with booleans as mask".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
df.as_ref()
|
||||
.filter(mask)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error filtering dataframe".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The only allowed column types for dummies are String or Int".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error filtering dataframe".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The only allowed column types for dummies are String or Int".into()),
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -70,14 +70,12 @@ fn command(
|
||||
|
||||
df.as_ref()
|
||||
.select(col_string)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error selecting columns".into(),
|
||||
e.to_string(),
|
||||
Some(col_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error selecting columns".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(col_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -152,38 +152,34 @@ fn command(
|
||||
let mut res = df
|
||||
.as_ref()
|
||||
.melt(&id_col_string, &val_col_string)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error calculating melt".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error calculating melt".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
if let Some(name) = &variable_name {
|
||||
res.rename("variable", &name.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error renaming column".into(),
|
||||
e.to_string(),
|
||||
Some(name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
res.rename("variable", &name.item)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error renaming column".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Some(name) = &value_name {
|
||||
res.rename("value", &name.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error renaming column".into(),
|
||||
e.to_string(),
|
||||
Some(name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
res.rename("value", &name.item)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error renaming column".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
@ -198,50 +194,50 @@ fn check_column_datatypes<T: AsRef<str>>(
|
||||
col_span: Span,
|
||||
) -> Result<(), ShellError> {
|
||||
if cols.is_empty() {
|
||||
return Err(ShellError::GenericError(
|
||||
"Merge error".into(),
|
||||
"empty column list".into(),
|
||||
Some(col_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Merge error".into(),
|
||||
msg: "empty column list".into(),
|
||||
span: Some(col_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
// Checking if they are same type
|
||||
if cols.len() > 1 {
|
||||
for w in cols.windows(2) {
|
||||
let l_series = df.column(w[0].as_ref()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error selecting columns".into(),
|
||||
e.to_string(),
|
||||
Some(col_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let l_series = df
|
||||
.column(w[0].as_ref())
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error selecting columns".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(col_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let r_series = df.column(w[1].as_ref()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error selecting columns".into(),
|
||||
e.to_string(),
|
||||
Some(col_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let r_series = df
|
||||
.column(w[1].as_ref())
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error selecting columns".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(col_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
if l_series.dtype() != r_series.dtype() {
|
||||
return Err(ShellError::GenericError(
|
||||
"Merge error".into(),
|
||||
"found different column types in list".into(),
|
||||
Some(col_span),
|
||||
Some(format!(
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Merge error".into(),
|
||||
msg: "found different column types in list".into(),
|
||||
span: Some(col_span),
|
||||
help: Some(format!(
|
||||
"datatypes {} and {} are incompatible",
|
||||
l_series.dtype(),
|
||||
r_series.dtype()
|
||||
)),
|
||||
Vec::new(),
|
||||
));
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,15 +121,15 @@ fn command(
|
||||
"json" => from_json(engine_state, stack, call),
|
||||
"jsonl" => from_jsonl(engine_state, stack, call),
|
||||
"avro" => from_avro(engine_state, stack, call),
|
||||
_ => Err(ShellError::FileNotFoundCustom(
|
||||
format!("{msg}. Supported values: csv, tsv, parquet, ipc, arrow, json"),
|
||||
blamed,
|
||||
)),
|
||||
_ => Err(ShellError::FileNotFoundCustom {
|
||||
msg: format!("{msg}. Supported values: csv, tsv, parquet, ipc, arrow, json"),
|
||||
span: blamed,
|
||||
}),
|
||||
},
|
||||
None => Err(ShellError::FileNotFoundCustom(
|
||||
"File without extension".into(),
|
||||
file.span,
|
||||
)),
|
||||
None => Err(ShellError::FileNotFoundCustom {
|
||||
msg: "File without extension".into(),
|
||||
span: file.span,
|
||||
}),
|
||||
}
|
||||
.map(|value| PipelineData::Value(value, None))
|
||||
}
|
||||
@ -150,17 +150,16 @@ fn from_parquet(
|
||||
low_memory: false,
|
||||
cloud_options: None,
|
||||
use_statistics: false,
|
||||
hive_partitioning: false,
|
||||
};
|
||||
|
||||
let df: NuLazyFrame = LazyFrame::scan_parquet(file, args)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Parquet reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Parquet reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -169,14 +168,12 @@ fn from_parquet(
|
||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
|
||||
|
||||
let r = File::open(&file.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error opening file".into(),
|
||||
e.to_string(),
|
||||
Some(file.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let r = File::open(&file.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error opening file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
let reader = ParquetReader::new(r);
|
||||
|
||||
@ -187,14 +184,12 @@ fn from_parquet(
|
||||
|
||||
let df: NuDataFrame = reader
|
||||
.finish()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Parquet reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Parquet reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -210,14 +205,12 @@ fn from_avro(
|
||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
|
||||
|
||||
let r = File::open(&file.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error opening file".into(),
|
||||
e.to_string(),
|
||||
Some(file.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let r = File::open(&file.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error opening file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
let reader = AvroReader::new(r);
|
||||
|
||||
@ -228,14 +221,12 @@ fn from_avro(
|
||||
|
||||
let df: NuDataFrame = reader
|
||||
.finish()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Avro reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Avro reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -258,14 +249,12 @@ fn from_ipc(
|
||||
};
|
||||
|
||||
let df: NuLazyFrame = LazyFrame::scan_ipc(file, args)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"IPC reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "IPC reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -274,14 +263,12 @@ fn from_ipc(
|
||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
|
||||
|
||||
let r = File::open(&file.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error opening file".into(),
|
||||
e.to_string(),
|
||||
Some(file.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let r = File::open(&file.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error opening file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
let reader = IpcReader::new(r);
|
||||
|
||||
@ -292,14 +279,12 @@ fn from_ipc(
|
||||
|
||||
let df: NuDataFrame = reader
|
||||
.finish()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"IPC reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "IPC reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -313,14 +298,12 @@ fn from_json(
|
||||
call: &Call,
|
||||
) -> Result<Value, ShellError> {
|
||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||
let file = File::open(&file.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error opening file".into(),
|
||||
e.to_string(),
|
||||
Some(file.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let file = File::open(&file.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error opening file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let buf_reader = BufReader::new(file);
|
||||
@ -328,14 +311,12 @@ fn from_json(
|
||||
|
||||
let df: NuDataFrame = reader
|
||||
.finish()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Json reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Json reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -349,14 +330,12 @@ fn from_jsonl(
|
||||
) -> Result<Value, ShellError> {
|
||||
let infer_schema: Option<usize> = call.get_flag(engine_state, stack, "infer-schema")?;
|
||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||
let file = File::open(&file.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error opening file".into(),
|
||||
e.to_string(),
|
||||
Some(file.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let file = File::open(&file.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error opening file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let buf_reader = BufReader::new(file);
|
||||
@ -366,14 +345,12 @@ fn from_jsonl(
|
||||
|
||||
let df: NuDataFrame = reader
|
||||
.finish()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Json lines reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Json lines reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -399,19 +376,19 @@ fn from_csv(
|
||||
None => csv_reader,
|
||||
Some(d) => {
|
||||
if d.item.len() != 1 {
|
||||
return Err(ShellError::GenericError(
|
||||
"Incorrect delimiter".into(),
|
||||
"Delimiter has to be one character".into(),
|
||||
Some(d.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Incorrect delimiter".into(),
|
||||
msg: "Delimiter has to be one character".into(),
|
||||
span: Some(d.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
} else {
|
||||
let delimiter = match d.item.chars().next() {
|
||||
Some(d) => d as u8,
|
||||
None => unreachable!(),
|
||||
};
|
||||
csv_reader.with_delimiter(delimiter)
|
||||
csv_reader.with_separator(delimiter)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -430,14 +407,12 @@ fn from_csv(
|
||||
|
||||
let df: NuLazyFrame = csv_reader
|
||||
.finish()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Parquet reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Parquet reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
@ -445,14 +420,12 @@ fn from_csv(
|
||||
} else {
|
||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||
let csv_reader = CsvReader::from_path(&file.item)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating CSV reader".into(),
|
||||
e.to_string(),
|
||||
Some(file.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating CSV reader".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.with_encoding(CsvEncoding::LossyUtf8);
|
||||
|
||||
@ -460,19 +433,19 @@ fn from_csv(
|
||||
None => csv_reader,
|
||||
Some(d) => {
|
||||
if d.item.len() != 1 {
|
||||
return Err(ShellError::GenericError(
|
||||
"Incorrect delimiter".into(),
|
||||
"Delimiter has to be one character".into(),
|
||||
Some(d.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Incorrect delimiter".into(),
|
||||
msg: "Delimiter has to be one character".into(),
|
||||
span: Some(d.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
} else {
|
||||
let delimiter = match d.item.chars().next() {
|
||||
Some(d) => d as u8,
|
||||
None => unreachable!(),
|
||||
};
|
||||
csv_reader.with_delimiter(delimiter)
|
||||
csv_reader.with_separator(delimiter)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -496,14 +469,12 @@ fn from_csv(
|
||||
|
||||
let df: NuDataFrame = csv_reader
|
||||
.finish()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Parquet reader error".into(),
|
||||
format!("{e:?}"),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Parquet reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
|
@ -76,15 +76,15 @@ fn command(
|
||||
|
||||
let mut ctx = SQLContext::new();
|
||||
ctx.register("df", &df.df);
|
||||
let df_sql = ctx.execute(&sql_query).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Dataframe Error".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let df_sql = ctx
|
||||
.execute(&sql_query)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Dataframe Error".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
let lazy = NuLazyFrame::new(false, df_sql);
|
||||
|
||||
let eager = lazy.collect(call.head)?;
|
||||
|
@ -130,15 +130,15 @@ fn command_eager(
|
||||
let new_names = extract_strings(new_names)?;
|
||||
|
||||
for (from, to) in columns.iter().zip(new_names.iter()) {
|
||||
df.as_mut().rename(from, to).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error renaming".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
df.as_mut()
|
||||
.rename(from, to)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error renaming".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(PipelineData::Value(df.into_value(call.head), None))
|
||||
|
@ -4,6 +4,8 @@ use nu_protocol::{
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type,
|
||||
};
|
||||
use polars::prelude::NamedFrom;
|
||||
use polars::series::Series;
|
||||
|
||||
use super::super::values::NuDataFrame;
|
||||
|
||||
@ -81,7 +83,7 @@ fn command(
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let rows: Option<Spanned<usize>> = call.get_flag(engine_state, stack, "n-rows")?;
|
||||
let rows: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "n-rows")?;
|
||||
let fraction: Option<Spanned<f64>> = call.get_flag(engine_state, stack, "fraction")?;
|
||||
let seed: Option<u64> = call
|
||||
.get_flag::<i64>(engine_state, stack, "seed")?
|
||||
@ -94,42 +96,38 @@ fn command(
|
||||
match (rows, fraction) {
|
||||
(Some(rows), None) => df
|
||||
.as_ref()
|
||||
.sample_n(rows.item, replace, shuffle, seed)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating sample".into(),
|
||||
e.to_string(),
|
||||
Some(rows.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.sample_n(&Series::new("s", &[rows.item]), replace, shuffle, seed)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating sample".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(rows.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
(None, Some(frac)) => df
|
||||
.as_ref()
|
||||
.sample_frac(frac.item, replace, shuffle, seed)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating sample".into(),
|
||||
e.to_string(),
|
||||
Some(frac.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.sample_frac(&Series::new("frac", &[frac.item]), replace, shuffle, seed)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating sample".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(frac.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
(Some(_), Some(_)) => Err(ShellError::GenericError(
|
||||
"Incompatible flags".into(),
|
||||
"Only one selection criterion allowed".into(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
(None, None) => Err(ShellError::GenericError(
|
||||
"No selection".into(),
|
||||
"No selection criterion was found".into(),
|
||||
Some(call.head),
|
||||
Some("Perhaps you want to use the flag -n or -f".into()),
|
||||
Vec::new(),
|
||||
)),
|
||||
(Some(_), Some(_)) => Err(ShellError::GenericError {
|
||||
error: "Incompatible flags".into(),
|
||||
msg: "Only one selection criterion allowed".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
(None, None) => Err(ShellError::GenericError {
|
||||
error: "No selection".into(),
|
||||
msg: "No selection criterion was found".into(),
|
||||
span: Some(call.head),
|
||||
help: Some("Perhaps you want to use the flag -n or -f".into()),
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ use crate::dataframe::eager::sql_expr::parse_sql_expr;
|
||||
use polars::error::{ErrString, PolarsError};
|
||||
use polars::prelude::{col, DataFrame, DataType, IntoLazy, LazyFrame};
|
||||
use sqlparser::ast::{
|
||||
Expr as SqlExpr, Select, SelectItem, SetExpr, Statement, TableFactor, Value as SQLValue,
|
||||
Expr as SqlExpr, GroupByExpr, Select, SelectItem, SetExpr, Statement, TableFactor,
|
||||
Value as SQLValue,
|
||||
};
|
||||
use sqlparser::dialect::GenericDialect;
|
||||
use sqlparser::parser::Parser;
|
||||
@ -29,7 +30,7 @@ impl SQLContext {
|
||||
fn execute_select(&self, select_stmt: &Select) -> Result<LazyFrame, PolarsError> {
|
||||
// Determine involved dataframe
|
||||
// Implicit join require some more work in query parsers, Explicit join are preferred for now.
|
||||
let tbl = select_stmt.from.get(0).ok_or_else(|| {
|
||||
let tbl = select_stmt.from.first().ok_or_else(|| {
|
||||
PolarsError::ComputeError(ErrString::from("No table found in select statement"))
|
||||
})?;
|
||||
let mut alias_map = HashMap::new();
|
||||
@ -37,7 +38,7 @@ impl SQLContext {
|
||||
TableFactor::Table { name, alias, .. } => {
|
||||
let tbl_name = name
|
||||
.0
|
||||
.get(0)
|
||||
.first()
|
||||
.ok_or_else(|| {
|
||||
PolarsError::ComputeError(ErrString::from(
|
||||
"No table found in select statement",
|
||||
@ -96,8 +97,13 @@ impl SQLContext {
|
||||
.collect::<Result<Vec<_>, PolarsError>>()?;
|
||||
// Check for group by
|
||||
// After projection since there might be number.
|
||||
let group_by = select_stmt
|
||||
.group_by
|
||||
let group_by = match &select_stmt.group_by {
|
||||
GroupByExpr::All =>
|
||||
Err(
|
||||
PolarsError::ComputeError("Group-By Error: Only positive number or expression are supported, not all".into())
|
||||
)?,
|
||||
GroupByExpr::Expressions(expressions) => expressions
|
||||
}
|
||||
.iter()
|
||||
.map(
|
||||
|e|match e {
|
||||
@ -182,7 +188,7 @@ impl SQLContext {
|
||||
))
|
||||
} else {
|
||||
let ast = ast
|
||||
.get(0)
|
||||
.first()
|
||||
.ok_or_else(|| PolarsError::ComputeError(ErrString::from("No statement found")))?;
|
||||
Ok(match ast {
|
||||
Statement::Query(query) => {
|
||||
|
@ -2,8 +2,8 @@ use polars::error::PolarsError;
|
||||
use polars::prelude::{col, lit, DataType, Expr, LiteralValue, PolarsResult as Result, TimeUnit};
|
||||
|
||||
use sqlparser::ast::{
|
||||
BinaryOperator as SQLBinaryOperator, DataType as SQLDataType, Expr as SqlExpr,
|
||||
Function as SQLFunction, Value as SqlValue, WindowType,
|
||||
ArrayElemTypeDef, BinaryOperator as SQLBinaryOperator, DataType as SQLDataType,
|
||||
Expr as SqlExpr, Function as SQLFunction, Value as SqlValue, WindowType,
|
||||
};
|
||||
|
||||
fn map_sql_polars_datatype(data_type: &SQLDataType) -> Result<DataType> {
|
||||
@ -13,7 +13,7 @@ fn map_sql_polars_datatype(data_type: &SQLDataType) -> Result<DataType> {
|
||||
| SQLDataType::Uuid
|
||||
| SQLDataType::Clob(_)
|
||||
| SQLDataType::Text
|
||||
| SQLDataType::String => DataType::Utf8,
|
||||
| SQLDataType::String(_) => DataType::Utf8,
|
||||
SQLDataType::Float(_) => DataType::Float32,
|
||||
SQLDataType::Real => DataType::Float32,
|
||||
SQLDataType::Double => DataType::Float64,
|
||||
@ -31,9 +31,12 @@ fn map_sql_polars_datatype(data_type: &SQLDataType) -> Result<DataType> {
|
||||
SQLDataType::Time(_, _) => DataType::Time,
|
||||
SQLDataType::Timestamp(_, _) => DataType::Datetime(TimeUnit::Microseconds, None),
|
||||
SQLDataType::Interval => DataType::Duration(TimeUnit::Microseconds),
|
||||
SQLDataType::Array(inner_type) => match inner_type {
|
||||
Some(inner_type) => DataType::List(Box::new(map_sql_polars_datatype(inner_type)?)),
|
||||
None => {
|
||||
SQLDataType::Array(array_type_def) => match array_type_def {
|
||||
ArrayElemTypeDef::AngleBracket(inner_type)
|
||||
| ArrayElemTypeDef::SquareBracket(inner_type) => {
|
||||
DataType::List(Box::new(map_sql_polars_datatype(inner_type)?))
|
||||
}
|
||||
_ => {
|
||||
return Err(PolarsError::ComputeError(
|
||||
"SQL Datatype Array(None) was not supported in polars-sql yet!".into(),
|
||||
))
|
||||
@ -114,7 +117,11 @@ pub fn parse_sql_expr(expr: &SqlExpr) -> Result<Expr> {
|
||||
binary_op_(left, right, op)?
|
||||
}
|
||||
SqlExpr::Function(sql_function) => parse_sql_function(sql_function)?,
|
||||
SqlExpr::Cast { expr, data_type } => cast_(parse_sql_expr(expr)?, data_type)?,
|
||||
SqlExpr::Cast {
|
||||
expr,
|
||||
data_type,
|
||||
format: _,
|
||||
} => cast_(parse_sql_expr(expr)?, data_type)?,
|
||||
SqlExpr::Nested(expr) => parse_sql_expr(expr)?,
|
||||
SqlExpr::Value(value) => literal_expr(value)?,
|
||||
_ => {
|
||||
|
@ -127,23 +127,23 @@ fn command(
|
||||
if (&0.0..=&1.0).contains(&val) {
|
||||
Ok(*val)
|
||||
} else {
|
||||
Err(ShellError::GenericError(
|
||||
"Incorrect value for quantile".to_string(),
|
||||
"value should be between 0 and 1".to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
))
|
||||
Err(ShellError::GenericError {
|
||||
error: "Incorrect value for quantile".into(),
|
||||
msg: "value should be between 0 and 1".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
Value::Error { error, .. } => Err(*error.clone()),
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect value for quantile".to_string(),
|
||||
"value should be a float".to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect value for quantile".into(),
|
||||
msg: "value should be a float".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<f64>, ShellError>>()
|
||||
@ -250,14 +250,12 @@ fn command(
|
||||
let res = head.chain(tail).collect::<Vec<Series>>();
|
||||
|
||||
DataFrame::new(res)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Dataframe Error".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Dataframe Error".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -97,47 +97,41 @@ fn command(
|
||||
let index = NuDataFrame::try_from_value(index_value)?.as_series(index_span)?;
|
||||
|
||||
let casted = match index.dtype() {
|
||||
DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => {
|
||||
index.cast(&DataType::UInt32).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting index list".into(),
|
||||
e.to_string(),
|
||||
Some(index_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
"Series with incorrect type".into(),
|
||||
Some(call.head),
|
||||
Some("Consider using a Series with type int type".into()),
|
||||
Vec::new(),
|
||||
)),
|
||||
DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => index
|
||||
.cast(&DataType::UInt32)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting index list".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(index_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect type".into(),
|
||||
msg: "Series with incorrect type".into(),
|
||||
span: Some(call.head),
|
||||
help: Some("Consider using a Series with type int type".into()),
|
||||
inner: vec![],
|
||||
}),
|
||||
}?;
|
||||
|
||||
let indices = casted.u32().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting index list".into(),
|
||||
e.to_string(),
|
||||
Some(index_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let indices = casted.u32().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting index list".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(index_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_pipeline(input, call.head).and_then(|df| {
|
||||
df.as_ref()
|
||||
.take(indices)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error taking values".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error taking values".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
})
|
||||
|
@ -58,25 +58,23 @@ fn command(
|
||||
|
||||
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let mut file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error with file name".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let mut file = File::create(&file_name.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error with file name".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
IpcWriter::new(&mut file).finish(df.as_mut()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error saving file".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
IpcWriter::new(&mut file)
|
||||
.finish(df.as_mut())
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error saving file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
|
@ -85,27 +85,23 @@ fn command(
|
||||
|
||||
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error with file name".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let file = File::create(&file_name.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error with file name".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
AvroWriter::new(file)
|
||||
.with_compression(compression)
|
||||
.finish(df.as_mut())
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error saving file".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error saving file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
@ -74,55 +74,53 @@ fn command(
|
||||
|
||||
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let mut file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error with file name".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let mut file = File::create(&file_name.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error with file name".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let writer = CsvWriter::new(&mut file);
|
||||
|
||||
let writer = if no_header {
|
||||
writer.has_header(false)
|
||||
writer.include_header(false)
|
||||
} else {
|
||||
writer.has_header(true)
|
||||
writer.include_header(true)
|
||||
};
|
||||
|
||||
let mut writer = match delimiter {
|
||||
None => writer,
|
||||
Some(d) => {
|
||||
if d.item.len() != 1 {
|
||||
return Err(ShellError::GenericError(
|
||||
"Incorrect delimiter".into(),
|
||||
"Delimiter has to be one char".into(),
|
||||
Some(d.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Incorrect delimiter".into(),
|
||||
msg: "Delimiter has to be one char".into(),
|
||||
span: Some(d.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
} else {
|
||||
let delimiter = match d.item.chars().next() {
|
||||
Some(d) => d as u8,
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
writer.with_delimiter(delimiter)
|
||||
writer.with_separator(delimiter)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
writer.finish(df.as_mut()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error writing to file".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
writer
|
||||
.finish(df.as_mut())
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error writing to file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
|
@ -58,27 +58,23 @@ fn command(
|
||||
|
||||
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error with file name".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let file = File::create(&file_name.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error with file name".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
let buf_writer = BufWriter::new(file);
|
||||
|
||||
JsonWriter::new(buf_writer)
|
||||
.finish(df.as_mut())
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error saving file".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error saving file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
@ -58,25 +58,23 @@ fn command(
|
||||
|
||||
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error with file name".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let file = File::create(&file_name.item).map_err(|e| ShellError::GenericError {
|
||||
error: "Error with file name".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
ParquetWriter::new(file).finish(df.as_mut()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error saving file".into(),
|
||||
e.to_string(),
|
||||
Some(file_name.span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
ParquetWriter::new(file)
|
||||
.finish(df.as_mut())
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error saving file".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(file_name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
|
@ -151,14 +151,12 @@ fn command_eager(
|
||||
|
||||
df.as_mut()
|
||||
.with_column(series)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error adding column to dataframe".into(),
|
||||
e.to_string(),
|
||||
Some(column_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error adding column to dataframe".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(column_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| {
|
||||
PipelineData::Value(
|
||||
|
@ -319,7 +319,7 @@ macro_rules! lazy_expr_command {
|
||||
expr_command!(
|
||||
ExprList,
|
||||
"dfr implode",
|
||||
"Aggregates a group to a Series",
|
||||
"Aggregates a group to a Series.",
|
||||
vec![Example {
|
||||
description: "",
|
||||
example: "",
|
||||
@ -334,7 +334,7 @@ expr_command!(
|
||||
expr_command!(
|
||||
ExprAggGroups,
|
||||
"dfr agg-groups",
|
||||
"creates an agg_groups expression",
|
||||
"Creates an agg_groups expression.",
|
||||
vec![Example {
|
||||
description: "",
|
||||
example: "",
|
||||
@ -349,7 +349,7 @@ expr_command!(
|
||||
expr_command!(
|
||||
ExprCount,
|
||||
"dfr count",
|
||||
"creates a count expression",
|
||||
"Creates a count expression.",
|
||||
vec![Example {
|
||||
description: "",
|
||||
example: "",
|
||||
@ -364,7 +364,7 @@ expr_command!(
|
||||
expr_command!(
|
||||
ExprNot,
|
||||
"dfr expr-not",
|
||||
"creates a not expression",
|
||||
"Creates a not expression.",
|
||||
vec![Example {
|
||||
description: "Creates a not expression",
|
||||
example: "(dfr col a) > 2) | dfr expr-not",
|
||||
@ -379,7 +379,7 @@ expr_command!(
|
||||
lazy_expr_command!(
|
||||
ExprMax,
|
||||
"dfr max",
|
||||
"Creates a max expression or aggregates columns to their max value",
|
||||
"Creates a max expression or aggregates columns to their max value.",
|
||||
vec![
|
||||
Example {
|
||||
description: "Max value from columns in a dataframe",
|
||||
@ -424,7 +424,7 @@ lazy_expr_command!(
|
||||
lazy_expr_command!(
|
||||
ExprMin,
|
||||
"dfr min",
|
||||
"Creates a min expression or aggregates columns to their min value",
|
||||
"Creates a min expression or aggregates columns to their min value.",
|
||||
vec![
|
||||
Example {
|
||||
description: "Min value from columns in a dataframe",
|
||||
@ -469,7 +469,7 @@ lazy_expr_command!(
|
||||
lazy_expr_command!(
|
||||
ExprSum,
|
||||
"dfr sum",
|
||||
"Creates a sum expression for an aggregation or aggregates columns to their sum value",
|
||||
"Creates a sum expression for an aggregation or aggregates columns to their sum value.",
|
||||
vec![
|
||||
Example {
|
||||
description: "Sums all columns in a dataframe",
|
||||
@ -514,7 +514,7 @@ lazy_expr_command!(
|
||||
lazy_expr_command!(
|
||||
ExprMean,
|
||||
"dfr mean",
|
||||
"Creates a mean expression for an aggregation or aggregates columns to their mean value",
|
||||
"Creates a mean expression for an aggregation or aggregates columns to their mean value.",
|
||||
vec![
|
||||
Example {
|
||||
description: "Mean value from columns in a dataframe",
|
||||
@ -559,7 +559,7 @@ lazy_expr_command!(
|
||||
expr_command!(
|
||||
ExprMedian,
|
||||
"dfr median",
|
||||
"Creates a median expression for an aggregation",
|
||||
"Creates a median expression for an aggregation.",
|
||||
vec![Example {
|
||||
description: "Median aggregation for a group-by",
|
||||
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
||||
@ -590,7 +590,7 @@ expr_command!(
|
||||
lazy_expr_command!(
|
||||
ExprStd,
|
||||
"dfr std",
|
||||
"Creates a std expression for an aggregation of std value from columns in a dataframe",
|
||||
"Creates a std expression for an aggregation of std value from columns in a dataframe.",
|
||||
vec![
|
||||
Example {
|
||||
description: "Std value from columns in a dataframe",
|
||||
@ -636,7 +636,7 @@ lazy_expr_command!(
|
||||
lazy_expr_command!(
|
||||
ExprVar,
|
||||
"dfr var",
|
||||
"Create a var expression for an aggregation",
|
||||
"Create a var expression for an aggregation.",
|
||||
vec![
|
||||
Example {
|
||||
description:
|
||||
|
@ -15,7 +15,7 @@ impl Command for ExprOtherwise {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"completes a when expression."
|
||||
"Completes a when expression."
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
|
@ -125,13 +125,13 @@ impl Command for LazyAggregate {
|
||||
let dtype = schema.get(name.as_str());
|
||||
|
||||
if matches!(dtype, Some(DataType::Object(..))) {
|
||||
return Err(ShellError::GenericError(
|
||||
"Object type column not supported for aggregation".into(),
|
||||
format!("Column '{name}' is type Object"),
|
||||
Some(call.head),
|
||||
Some("Aggregations cannot be performed on Object type columns. Use dtype command to check column types".into()),
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Object type column not supported for aggregation".into(),
|
||||
msg: format!("Column '{name}' is type Object"),
|
||||
span: Some(call.head),
|
||||
help: Some("Aggregations cannot be performed on Object type columns. Use dtype command to check column types".into()),
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -171,7 +171,7 @@ fn get_col_name(expr: &Expr) -> Option<String> {
|
||||
| Expr::Slice { input: expr, .. }
|
||||
| Expr::Cast { expr, .. }
|
||||
| Expr::Sort { expr, .. }
|
||||
| Expr::Take { expr, .. }
|
||||
| Expr::Gather { expr, .. }
|
||||
| Expr::SortBy { expr, .. }
|
||||
| Expr::Exclude(expr, _)
|
||||
| Expr::Alias(expr, _)
|
||||
@ -189,6 +189,7 @@ fn get_col_name(expr: &Expr) -> Option<String> {
|
||||
| Expr::RenameAlias { .. }
|
||||
| Expr::Count
|
||||
| Expr::Nth(_)
|
||||
| Expr::SubPlan(_, _)
|
||||
| Expr::Selector(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ impl Command for LazyFetch {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"collects the lazyframe to the selected rows."
|
||||
"Collects the lazyframe to the selected rows."
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
@ -67,14 +67,12 @@ impl Command for LazyFetch {
|
||||
let eager: NuDataFrame = lazy
|
||||
.into_polars()
|
||||
.fetch(rows as usize)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error fetching rows".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error fetching rows".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
|
||||
|
@ -17,7 +17,7 @@ impl Command for LazyFlatten {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"An alias for dfr explode"
|
||||
"An alias for dfr explode."
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
|
@ -121,7 +121,7 @@ lazy_command!(
|
||||
"dfr reverse",
|
||||
"Reverses the LazyFrame",
|
||||
vec![Example {
|
||||
description: "Reverses the dataframe",
|
||||
description: "Reverses the dataframe.",
|
||||
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr reverse",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
@ -147,7 +147,7 @@ lazy_command!(
|
||||
lazy_command!(
|
||||
LazyCache,
|
||||
"dfr cache",
|
||||
"Caches operations in a new LazyFrame",
|
||||
"Caches operations in a new LazyFrame.",
|
||||
vec![Example {
|
||||
description: "Caches the result into a new LazyFrame",
|
||||
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr reverse | dfr cache",
|
||||
|
@ -16,7 +16,7 @@ impl Command for LazySortBy {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"sorts a lazy dataframe based on expression(s)."
|
||||
"Sorts a lazy dataframe based on expression(s)."
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
@ -118,13 +118,13 @@ impl Command for LazySortBy {
|
||||
.get_flag::<Value>(engine_state, stack, "reverse")?
|
||||
.expect("already checked and it exists")
|
||||
.span();
|
||||
return Err(ShellError::GenericError(
|
||||
"Incorrect list size".into(),
|
||||
"Size doesn't match expression list".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Incorrect list size".into(),
|
||||
msg: "Size doesn't match expression list".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
} else {
|
||||
list
|
||||
}
|
||||
|
@ -78,14 +78,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let series = df.as_series(call.head)?;
|
||||
let bool = series.bool().map_err(|_| {
|
||||
ShellError::GenericError(
|
||||
"Error converting to bool".into(),
|
||||
"all-false only works with series of type bool".into(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let bool = series.bool().map_err(|_| ShellError::GenericError {
|
||||
error: "Error converting to bool".into(),
|
||||
msg: "all-false only works with series of type bool".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let value = Value::bool(!bool.any(), call.head);
|
||||
|
@ -78,14 +78,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let series = df.as_series(call.head)?;
|
||||
let bool = series.bool().map_err(|_| {
|
||||
ShellError::GenericError(
|
||||
"Error converting to bool".into(),
|
||||
"all-false only works with series of type bool".into(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let bool = series.bool().map_err(|_| ShellError::GenericError {
|
||||
error: "Error converting to bool".into(),
|
||||
msg: "all-false only works with series of type bool".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let value = Value::bool(bool.all(), call.head);
|
||||
|
@ -8,6 +8,7 @@ use nu_protocol::{
|
||||
Value,
|
||||
};
|
||||
use polars::prelude::{DataType, IntoSeries};
|
||||
use polars_ops::prelude::{cum_max, cum_min, cum_sum};
|
||||
|
||||
enum CumType {
|
||||
Min,
|
||||
@ -21,13 +22,13 @@ impl CumType {
|
||||
"min" => Ok(Self::Min),
|
||||
"max" => Ok(Self::Max),
|
||||
"sum" => Ok(Self::Sum),
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Wrong operation".into(),
|
||||
"Operation not valid for cumulative".into(),
|
||||
Some(span),
|
||||
Some("Allowed values: max, min, sum".into()),
|
||||
Vec::new(),
|
||||
)),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Wrong operation".into(),
|
||||
msg: "Operation not valid for cumulative".into(),
|
||||
span: Some(span),
|
||||
help: Some("Allowed values: max, min, sum".into()),
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,21 +109,28 @@ fn command(
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
if let DataType::Object(_) = series.dtype() {
|
||||
return Err(ShellError::GenericError(
|
||||
"Found object series".into(),
|
||||
"Series of type object cannot be used for cumulative operation".into(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Found object series".into(),
|
||||
msg: "Series of type object cannot be used for cumulative operation".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
let cum_type = CumType::from_str(&cum_type.item, cum_type.span)?;
|
||||
let mut res = match cum_type {
|
||||
CumType::Max => series.cummax(reverse),
|
||||
CumType::Min => series.cummin(reverse),
|
||||
CumType::Sum => series.cumsum(reverse),
|
||||
};
|
||||
CumType::Max => cum_max(&series, reverse),
|
||||
CumType::Min => cum_min(&series, reverse),
|
||||
CumType::Sum => cum_sum(&series, reverse),
|
||||
}
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating cumulative".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let name = format!("{}_{}", series.name(), cum_type.to_str());
|
||||
res.rename(&name);
|
||||
|
@ -68,14 +68,12 @@ fn command(
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
let casted = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = if not_exact {
|
||||
@ -85,14 +83,12 @@ fn command(
|
||||
};
|
||||
|
||||
let mut res = res
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating datetime".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating datetime".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
|
@ -132,14 +132,12 @@ fn command(
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
let casted = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = if not_exact {
|
||||
@ -162,14 +160,12 @@ fn command(
|
||||
};
|
||||
|
||||
let mut res = res
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating datetime".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating datetime".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.day().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.hour().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.minute().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.month().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.nanosecond().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.ordinal().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.second().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.week().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.weekday().into_series();
|
||||
|
@ -65,14 +65,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to datetime type".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted.year().into_series();
|
||||
|
@ -67,13 +67,13 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let columns = df.as_ref().get_column_names();
|
||||
if columns.len() > 1 {
|
||||
return Err(ShellError::GenericError(
|
||||
"Error using as series".into(),
|
||||
"dataframe has more than one column".into(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Error using as series".into(),
|
||||
msg: "dataframe has more than one column".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
match columns.first() {
|
||||
@ -85,14 +85,12 @@ fn command(
|
||||
.lazy()
|
||||
.select(&[expression])
|
||||
.collect()
|
||||
.map_err(|err| {
|
||||
ShellError::GenericError(
|
||||
"Error creating index column".into(),
|
||||
err.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "Error creating index column".into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let value = NuDataFrame::dataframe_into_value(res, call.head);
|
||||
|
@ -69,14 +69,12 @@ fn command(
|
||||
let mut res = df
|
||||
.as_series(call.head)?
|
||||
.arg_unique()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error extracting unique values".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error extracting unique values".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
res.rename("arg_unique");
|
||||
|
@ -86,36 +86,33 @@ fn command(
|
||||
let indices = NuDataFrame::try_from_value(indices_value)?.as_series(indices_span)?;
|
||||
|
||||
let casted = match indices.dtype() {
|
||||
DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => {
|
||||
indices.as_ref().cast(&DataType::UInt32).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting indices".into(),
|
||||
e.to_string(),
|
||||
Some(indices_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
"Series with incorrect type".into(),
|
||||
Some(indices_span),
|
||||
Some("Consider using a Series with type int type".into()),
|
||||
Vec::new(),
|
||||
)),
|
||||
DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => indices
|
||||
.as_ref()
|
||||
.cast(&DataType::UInt32)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting indices".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(indices_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect type".into(),
|
||||
msg: "Series with incorrect type".into(),
|
||||
span: Some(indices_span),
|
||||
help: Some("Consider using a Series with type int type".into()),
|
||||
inner: vec![],
|
||||
}),
|
||||
}?;
|
||||
|
||||
let indices = casted
|
||||
.u32()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting indices".into(),
|
||||
e.to_string(),
|
||||
Some(indices_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting indices".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(indices_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_iter()
|
||||
.flatten();
|
||||
@ -124,92 +121,85 @@ fn command(
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let span = value.span();
|
||||
let res = match value {
|
||||
Value::Int { val, .. } => {
|
||||
let chunked = series.i64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to i64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error setting value".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
let chunked = series.f64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to f64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error setting value".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::String { val, .. } => {
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = chunked
|
||||
.set_at_idx(indices, Some(val.as_ref()))
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error setting value".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let res =
|
||||
match value {
|
||||
Value::Int { val, .. } => {
|
||||
let chunked = series.i64().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to i64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = res.into_series();
|
||||
res.rename("string");
|
||||
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
|
||||
ShellError::GenericError {
|
||||
error: "Error setting value".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect value type".into(),
|
||||
format!(
|
||||
"this value cannot be set in a series of type '{}'",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
};
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
let chunked = series.f64().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to f64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
|
||||
ShellError::GenericError {
|
||||
error: "Error setting value".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::String { val, .. } => {
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = chunked
|
||||
.set_at_idx(indices, Some(val.as_ref()))
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error setting value".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = res.into_series();
|
||||
res.rename("string");
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect value type".into(),
|
||||
msg: format!(
|
||||
"this value cannot be set in a series of type '{}'",
|
||||
series.dtype()
|
||||
),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
};
|
||||
|
||||
res.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||
}
|
||||
|
@ -94,14 +94,12 @@ fn command(
|
||||
let mut res = df
|
||||
.as_ref()
|
||||
.is_duplicated()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error finding duplicates".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error finding duplicates".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
|
@ -79,14 +79,12 @@ fn command(
|
||||
let other = other_df.as_series(other_span)?;
|
||||
|
||||
let mut res = is_in(&df, &other)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error finding in other".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error finding in other".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
|
@ -93,14 +93,12 @@ fn command(
|
||||
let mut res = df
|
||||
.as_ref()
|
||||
.is_unique()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error finding unique values".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error finding unique values".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
|
@ -68,14 +68,12 @@ fn command(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let bool = series.bool().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error inverting mask".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let bool = series.bool().map_err(|e| ShellError::GenericError {
|
||||
error: "Error inverting mask".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = bool.not();
|
||||
|
@ -85,22 +85,20 @@ fn command(
|
||||
let mask = NuDataFrame::try_from_value(mask_value)?.as_series(mask_span)?;
|
||||
|
||||
let bool_mask = match mask.dtype() {
|
||||
DataType::Boolean => mask.bool().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to bool".into(),
|
||||
e.to_string(),
|
||||
Some(mask_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
DataType::Boolean => mask.bool().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to bool".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(mask_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect type".into(),
|
||||
msg: "can only use bool series as mask".into(),
|
||||
span: Some(mask_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
"can only use bool series as mask".into(),
|
||||
Some(mask_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
}?;
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
@ -108,70 +106,64 @@ fn command(
|
||||
let span = value.span();
|
||||
let res = match value {
|
||||
Value::Int { val, .. } => {
|
||||
let chunked = series.i64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to i64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.i64().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to i64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = chunked.set(bool_mask, Some(val)).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error setting value".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let res = chunked
|
||||
.set(bool_mask, Some(val))
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error setting value".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
let chunked = series.f64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to f64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.f64().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to f64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = chunked.set(bool_mask, Some(val)).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error setting value".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let res = chunked
|
||||
.set(bool_mask, Some(val))
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error setting value".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::String { val, .. } => {
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = chunked.set(bool_mask, Some(val.as_ref())).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error setting value".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
ShellError::GenericError {
|
||||
error: "Error setting value".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}
|
||||
})?;
|
||||
|
||||
let mut res = res.into_series();
|
||||
@ -179,16 +171,16 @@ fn command(
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect value type".into(),
|
||||
format!(
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect value type".into(),
|
||||
msg: format!(
|
||||
"this value cannot be set in a series of type '{}'",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
};
|
||||
|
||||
res.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||
|
@ -83,15 +83,16 @@ fn command(
|
||||
call: &Call,
|
||||
df: NuDataFrame,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let res = df.as_series(call.head)?.n_unique().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error counting unique values".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let res = df
|
||||
.as_series(call.head)?
|
||||
.n_unique()
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error counting unique values".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let value = Value::int(res as i64, call.head);
|
||||
|
||||
|
@ -23,13 +23,13 @@ impl RollType {
|
||||
"max" => Ok(Self::Max),
|
||||
"sum" => Ok(Self::Sum),
|
||||
"mean" => Ok(Self::Mean),
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Wrong operation".into(),
|
||||
"Operation not valid for cumulative".into(),
|
||||
Some(span),
|
||||
Some("Allowed values: min, max, sum, mean".into()),
|
||||
Vec::new(),
|
||||
)),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Wrong operation".into(),
|
||||
msg: "Operation not valid for cumulative".into(),
|
||||
span: Some(span),
|
||||
help: Some("Allowed values: min, max, sum, mean".into()),
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,13 +129,13 @@ fn command(
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
if let DataType::Object(_) = series.dtype() {
|
||||
return Err(ShellError::GenericError(
|
||||
"Found object series".into(),
|
||||
"Series of type object cannot be used for rolling operation".into(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Found object series".into(),
|
||||
msg: "Series of type object cannot be used for rolling operation".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
let roll_type = RollType::from_str(&roll_type.item, roll_type.span)?;
|
||||
@ -158,14 +158,12 @@ fn command(
|
||||
RollType::Mean => series.rolling_mean(rolling_opts),
|
||||
};
|
||||
|
||||
let mut res = res.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error calculating rolling values".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let mut res = res.map_err(|e| ShellError::GenericError {
|
||||
error: "Error calculating rolling values".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let name = format!("{}_{}", series.name(), roll_type.to_str());
|
||||
|
@ -9,6 +9,8 @@ use nu_protocol::{
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||
};
|
||||
|
||||
use polars_plan::prelude::lit;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Shift;
|
||||
|
||||
@ -98,7 +100,7 @@ fn command_lazy(
|
||||
let lazy: NuLazyFrame = match fill {
|
||||
Some(fill) => {
|
||||
let expr = NuExpression::try_from_value(fill)?.into_polars();
|
||||
lazy.shift_and_fill(shift, expr).into()
|
||||
lazy.shift_and_fill(lit(shift), expr).into()
|
||||
}
|
||||
None => lazy.shift(shift).into(),
|
||||
};
|
||||
|
@ -78,25 +78,21 @@ fn command(
|
||||
let other_df = NuDataFrame::try_from_value(other)?;
|
||||
|
||||
let other_series = other_df.as_series(other_span)?;
|
||||
let other_chunked = other_series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"The concatenate only with string columns".into(),
|
||||
e.to_string(),
|
||||
Some(other_span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let other_chunked = other_series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "The concatenate only with string columns".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(other_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let series = df.as_series(call.head)?;
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"The concatenate only with string columns".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "The concatenate only with string columns".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = chunked.concat(other_chunked);
|
||||
|
@ -74,25 +74,23 @@ fn command(
|
||||
let pattern: String = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let series = df.as_series(call.head)?;
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"The contains command only with string columns".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "The contains command only with string columns".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = chunked.contains(&pattern, false).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error searching in series".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let res = chunked
|
||||
.contains(&pattern, false)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error searching in series".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||
|
@ -86,25 +86,23 @@ fn command(
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error conversion to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error conversion to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = chunked.replace(&pattern, &replace).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error finding pattern other".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let mut res = chunked
|
||||
.replace(&pattern, &replace)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error finding pattern other".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
res.rename(series.name());
|
||||
|
||||
|
@ -86,25 +86,24 @@ fn command(
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error conversion to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error conversion to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = chunked.replace_all(&pattern, &replace).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error finding pattern other".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let mut res =
|
||||
chunked
|
||||
.replace_all(&pattern, &replace)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error finding pattern other".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
res.rename(series.name());
|
||||
|
||||
|
@ -63,17 +63,15 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The str-lengths command can only be used with string columns".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The str-lengths command can only be used with string columns".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = chunked.as_ref().str_lengths().into_series();
|
||||
let res = chunked.as_ref().str_len_bytes().into_series();
|
||||
|
||||
NuDataFrame::try_from_series(vec![res], call.head)
|
||||
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||
|
@ -75,25 +75,15 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The str-slice command can only be used with string columns".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
let chunked = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The str-slice command can only be used with string columns".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = chunked.str_slice(start, length).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error slicing series".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let mut res = chunked.str_slice(start, length);
|
||||
res.rename(series.name());
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
|
@ -72,26 +72,22 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to date".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The str-slice command can only be used with string columns".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to date".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The str-slice command can only be used with string columns".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let res = casted
|
||||
.strftime(&fmt)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error formatting datetime".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error formatting datetime".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
|
@ -67,14 +67,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The str-slice command can only be used with string columns".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The str-slice command can only be used with string columns".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = casted.to_lowercase();
|
||||
|
@ -71,14 +71,12 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let casted = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The str-slice command can only be used with string columns".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The str-slice command can only be used with string columns".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let mut res = casted.to_uppercase();
|
||||
|
@ -96,14 +96,12 @@ fn command_eager(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let res = series.unique().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error calculating unique values".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The str-slice command can only be used with string columns".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
let res = series.unique().map_err(|e| ShellError::GenericError {
|
||||
error: "Error calculating unique values".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The str-slice command can only be used with string columns".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
|
@ -70,15 +70,15 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let res = series.value_counts(false, false).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error calculating value counts values".into(),
|
||||
e.to_string(),
|
||||
Some(call.head),
|
||||
Some("The str-slice command can only be used with string columns".into()),
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let res = series
|
||||
.value_counts(false, false)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error calculating value counts values".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(call.head),
|
||||
help: Some("The str-slice command can only be used with string columns".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
NuDataFrame::dataframe_into_value(res, call.head),
|
||||
|
@ -68,13 +68,13 @@ pub(super) fn compute_between_series(
|
||||
res.rename(&name);
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Division error".into(),
|
||||
e.to_string(),
|
||||
Some(right.span()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Division error".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(right.span()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
Operator::Comparison(Comparison::Equal) => {
|
||||
@ -119,13 +119,13 @@ pub(super) fn compute_between_series(
|
||||
res.rename(&name);
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incompatible types".into(),
|
||||
"unable to cast to boolean".into(),
|
||||
Some(right.span()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incompatible types".into(),
|
||||
msg: "unable to cast to boolean".into(),
|
||||
span: Some(right.span()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::IncompatibleParametersSingle {
|
||||
@ -148,13 +148,13 @@ pub(super) fn compute_between_series(
|
||||
res.rename(&name);
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incompatible types".into(),
|
||||
"unable to cast to boolean".into(),
|
||||
Some(right.span()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incompatible types".into(),
|
||||
msg: "unable to cast to boolean".into(),
|
||||
span: Some(right.span()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::IncompatibleParametersSingle {
|
||||
@ -186,14 +186,12 @@ where
|
||||
F: Fn(&'s Series, &'s Series) -> Result<ChunkedArray<BooleanType>, PolarsError>,
|
||||
{
|
||||
let mut res = f(lhs, rhs)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Equality error".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Equality error".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
@ -458,29 +456,29 @@ where
|
||||
let casted = series.i64();
|
||||
compute_casted_i64(casted, val, f, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to i64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to i64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
DataType::Int64 => {
|
||||
let casted = series.i64();
|
||||
compute_casted_i64(casted, val, f, span)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
format!(
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect type".into(),
|
||||
msg: format!(
|
||||
"Series of type {} can not be used for operations with an i64 value",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,13 +497,13 @@ where
|
||||
let res = res.into_series();
|
||||
NuDataFrame::series_to_value(res, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to i64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to i64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,29 +520,29 @@ where
|
||||
let casted = series.f64();
|
||||
compute_casted_f64(casted, val, f, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to f64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to f64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
DataType::Float64 => {
|
||||
let casted = series.f64();
|
||||
compute_casted_f64(casted, val, f, span)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
format!(
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect type".into(),
|
||||
msg: format!(
|
||||
"Series of type {} can not be used for operations with a float value",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,13 +561,13 @@ where
|
||||
let res = res.into_series();
|
||||
NuDataFrame::series_to_value(res, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to f64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to f64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,13 +584,13 @@ where
|
||||
let casted = series.i64();
|
||||
compare_casted_i64(casted, val, f, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to f64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to f64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
DataType::Date => {
|
||||
@ -607,29 +605,29 @@ where
|
||||
.expect("already checked for casting");
|
||||
compare_casted_i64(Ok(&casted), val, f, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to f64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to f64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
DataType::Int64 => {
|
||||
let casted = series.i64();
|
||||
compare_casted_i64(casted, val, f, span)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
format!(
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect type".into(),
|
||||
msg: format!(
|
||||
"Series of type {} can not be used for operations with an i64 value",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,13 +646,13 @@ where
|
||||
let res = res.into_series();
|
||||
NuDataFrame::series_to_value(res, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to i64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to i64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -671,29 +669,29 @@ where
|
||||
let casted = series.f64();
|
||||
compare_casted_f64(casted, val, f, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to i64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to i64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
DataType::Float64 => {
|
||||
let casted = series.f64();
|
||||
compare_casted_f64(casted, val, f, span)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
format!(
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Incorrect type".into(),
|
||||
msg: format!(
|
||||
"Series of type {} can not be used for operations with a float value",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -712,13 +710,13 @@ where
|
||||
let res = res.into_series();
|
||||
NuDataFrame::series_to_value(res, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to f64".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to f64".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -733,22 +731,22 @@ fn contains_series_pat(series: &Series, pat: &str, span: Span) -> Result<Value,
|
||||
let res = res.into_series();
|
||||
NuDataFrame::series_to_value(res, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Error using contains".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Error using contains".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to string".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -761,12 +759,12 @@ fn add_string_to_series(series: &Series, pat: &str, span: Span) -> Result<Value,
|
||||
|
||||
NuDataFrame::series_to_value(res, span)
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Unable to cast to string".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Unable to cast to string".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,12 @@ use polars::chunked_array::builder::AnonymousOwnedListBuilder;
|
||||
use polars::chunked_array::object::builder::ObjectChunkedBuilder;
|
||||
use polars::chunked_array::ChunkedArray;
|
||||
use polars::datatypes::AnyValue;
|
||||
use polars::export::arrow::array::{
|
||||
Array, BooleanArray, Float32Array, Float64Array, Int16Array, Int32Array, Int64Array, Int8Array,
|
||||
UInt16Array, UInt32Array, UInt64Array, UInt8Array,
|
||||
};
|
||||
use polars::export::arrow::Either;
|
||||
use polars::prelude::{
|
||||
ArrayRef, DataFrame, DataType, DatetimeChunked, Float64Type, Int64Type, IntoSeries,
|
||||
LargeBinaryArray, LargeListArray, LargeStringArray, ListBooleanChunkedBuilder,
|
||||
ListBuilderTrait, ListPrimitiveChunkedBuilder, ListType, ListUtf8ChunkedBuilder, NamedFrom,
|
||||
NewChunkedArray, ObjectType, Series, StructArray, TemporalMethods, TimeUnit,
|
||||
DataFrame, DataType, DatetimeChunked, Float64Type, Int64Type, IntoSeries,
|
||||
ListBooleanChunkedBuilder, ListBuilderTrait, ListPrimitiveChunkedBuilder, ListType,
|
||||
ListUtf8ChunkedBuilder, NamedFrom, NewChunkedArray, ObjectType, Series, TemporalMethods,
|
||||
TimeUnit,
|
||||
};
|
||||
|
||||
use nu_protocol::{Record, ShellError, Span, Value};
|
||||
@ -295,14 +291,12 @@ pub fn from_parsed_columns(column_values: ColumnMap) -> Result<NuDataFrame, Shel
|
||||
|
||||
DataFrame::new(df_series)
|
||||
.map(|df| NuDataFrame::new(false, df))
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating dataframe".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating dataframe".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -322,16 +316,14 @@ fn input_type_list_to_series(
|
||||
list_type: &InputType,
|
||||
values: &[Value],
|
||||
) -> Result<Series, ShellError> {
|
||||
let inconsistent_error = |_| {
|
||||
ShellError::GenericError(
|
||||
format!(
|
||||
"column {name} contains a list with inconsistent types: Expecting: {list_type:?}"
|
||||
),
|
||||
"".to_string(),
|
||||
None,
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let inconsistent_error = |_| ShellError::GenericError {
|
||||
error: format!(
|
||||
"column {name} contains a list with inconsistent types: Expecting: {list_type:?}"
|
||||
),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
match *list_type {
|
||||
// list of boolean values
|
||||
@ -431,14 +423,12 @@ fn input_type_list_to_series(
|
||||
|
||||
builder
|
||||
.append_series(&dt_chunked.into_series())
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error appending to series".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error appending to series".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?
|
||||
}
|
||||
let res = builder.finish();
|
||||
@ -471,14 +461,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::UInt8 => {
|
||||
let casted = series.u8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to u8".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.u8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to u8".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -496,14 +484,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::UInt16 => {
|
||||
let casted = series.u16().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to u16".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.u16().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to u16".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -521,14 +507,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::UInt32 => {
|
||||
let casted = series.u32().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to u32".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.u32().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to u32".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -546,14 +530,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::UInt64 => {
|
||||
let casted = series.u64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to u64".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.u64().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to u64".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -571,14 +553,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Int8 => {
|
||||
let casted = series.i8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to i8".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.i8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to i8".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -596,14 +576,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Int16 => {
|
||||
let casted = series.i16().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to i16".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.i16().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to i16".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -621,14 +599,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Int32 => {
|
||||
let casted = series.i32().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to i32".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.i32().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to i32".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -646,14 +622,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Int64 => {
|
||||
let casted = series.i64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to i64".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.i64().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to i64".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -671,14 +645,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Float32 => {
|
||||
let casted = series.f32().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to f32".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.f32().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to f32".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -696,14 +668,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Float64 => {
|
||||
let casted = series.f64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to f64".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.f64().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to f64".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -721,14 +691,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Boolean => {
|
||||
let casted = series.bool().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to bool".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.bool().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to bool".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -746,14 +714,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Utf8 => {
|
||||
let casted = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to string".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.utf8().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to string".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -776,13 +742,13 @@ fn series_to_values(
|
||||
.downcast_ref::<ChunkedArray<ObjectType<DataFrameValue>>>();
|
||||
|
||||
match casted {
|
||||
None => Err(ShellError::GenericError(
|
||||
"Error casting object from series".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(format!("Object not supported for conversion: {x}")),
|
||||
Vec::new(),
|
||||
)),
|
||||
None => Err(ShellError::GenericError {
|
||||
error: "Error casting object from series".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(format!("Object not supported for conversion: {x}")),
|
||||
inner: vec![],
|
||||
}),
|
||||
Some(ca) => {
|
||||
let it = ca.into_iter();
|
||||
let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row)
|
||||
@ -804,13 +770,13 @@ fn series_to_values(
|
||||
DataType::List(x) => {
|
||||
let casted = series.as_any().downcast_ref::<ChunkedArray<ListType>>();
|
||||
match casted {
|
||||
None => Err(ShellError::GenericError(
|
||||
"Error casting list from series".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(format!("List not supported for conversion: {x}")),
|
||||
Vec::new(),
|
||||
)),
|
||||
None => Err(ShellError::GenericError {
|
||||
error: "Error casting list from series".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(format!("List not supported for conversion: {x}")),
|
||||
inner: vec![],
|
||||
}),
|
||||
Some(ca) => {
|
||||
let it = ca.into_iter();
|
||||
if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) {
|
||||
@ -832,14 +798,12 @@ fn series_to_values(
|
||||
}
|
||||
}
|
||||
DataType::Date => {
|
||||
let casted = series.date().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to date".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.date().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to date".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -860,14 +824,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Datetime(time_unit, tz) => {
|
||||
let casted = series.datetime().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to datetime".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.datetime().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to datetime".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
@ -889,14 +851,12 @@ fn series_to_values(
|
||||
Ok(values)
|
||||
}
|
||||
DataType::Struct(polar_fields) => {
|
||||
let casted = series.struct_().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to struct".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
let casted = series.struct_().map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to struct".into(),
|
||||
msg: "".to_string(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: Vec::new(),
|
||||
})?;
|
||||
let it = casted.into_iter();
|
||||
let values: Result<Vec<Value>, ShellError> =
|
||||
@ -921,15 +881,16 @@ fn series_to_values(
|
||||
values
|
||||
}
|
||||
DataType::Time => {
|
||||
let casted = series.timestamp(TimeUnit::Nanoseconds).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting column to time".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
let casted =
|
||||
series
|
||||
.timestamp(TimeUnit::Nanoseconds)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error casting column to time".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(e.to_string()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let it = casted.into_iter();
|
||||
let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) {
|
||||
@ -945,13 +906,13 @@ fn series_to_values(
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
e => Err(ShellError::GenericError(
|
||||
"Error creating Dataframe".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(format!("Value not supported in nushell: {e}")),
|
||||
Vec::new(),
|
||||
)),
|
||||
e => Err(ShellError::GenericError {
|
||||
error: "Error creating Dataframe".into(),
|
||||
msg: "".to_string(),
|
||||
span: None,
|
||||
help: Some(format!("Value not supported in nushell: {e}")),
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -994,19 +955,20 @@ fn any_value_to_value(any_value: &AnyValue, span: Span) -> Result<Value, ShellEr
|
||||
AnyValue::List(series) => {
|
||||
series_to_values(series, None, None, span).map(|values| Value::list(values, span))
|
||||
}
|
||||
AnyValue::Struct(idx, struct_array, s_fields) => {
|
||||
let cols: Vec<String> = s_fields.iter().map(|f| f.name().to_string()).collect();
|
||||
let vals: Result<Vec<Value>, ShellError> = struct_array
|
||||
.values()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(pos, v)| {
|
||||
let f = &s_fields[pos];
|
||||
arr_to_value(&f.dtype, &**v, *idx, span)
|
||||
})
|
||||
.collect();
|
||||
let record = Record { cols, vals: vals? };
|
||||
Ok(Value::record(record, span))
|
||||
AnyValue::Struct(_idx, _struct_array, _s_fields) => {
|
||||
// This should convert to a StructOwned object.
|
||||
let static_value =
|
||||
any_value
|
||||
.clone()
|
||||
.into_static()
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Cannot convert polars struct to static value".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: Vec::new(),
|
||||
})?;
|
||||
any_value_to_value(&static_value, span)
|
||||
}
|
||||
AnyValue::StructOwned(struct_tuple) => {
|
||||
let values: Result<Vec<Value>, ShellError> = struct_tuple
|
||||
@ -1030,112 +992,13 @@ fn any_value_to_value(any_value: &AnyValue, span: Span) -> Result<Value, ShellEr
|
||||
AnyValue::Utf8Owned(s) => Ok(Value::string(s.to_string(), span)),
|
||||
AnyValue::Binary(bytes) => Ok(Value::binary(*bytes, span)),
|
||||
AnyValue::BinaryOwned(bytes) => Ok(Value::binary(bytes.to_owned(), span)),
|
||||
e => Err(ShellError::GenericError(
|
||||
"Error creating Value".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(format!("Value not supported in nushell: {e}")),
|
||||
Vec::new(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn arr_to_value(
|
||||
dt: &DataType,
|
||||
arr: &dyn Array,
|
||||
idx: usize,
|
||||
span: Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
macro_rules! downcast {
|
||||
($casttype:ident) => {{
|
||||
let arr = &*(arr as *const dyn Array as *const $casttype);
|
||||
arr.value_unchecked(idx)
|
||||
}};
|
||||
}
|
||||
|
||||
// Not loving the unsafe here, however this largely based off the one
|
||||
// example I found for converting Array values in:
|
||||
// polars_core::chunked_array::ops::any_value::arr_to_any_value
|
||||
unsafe {
|
||||
match dt {
|
||||
DataType::Boolean => Ok(Value::bool(downcast!(BooleanArray), span)),
|
||||
DataType::UInt8 => Ok(Value::int(downcast!(UInt8Array) as i64, span)),
|
||||
DataType::UInt16 => Ok(Value::int(downcast!(UInt16Array) as i64, span)),
|
||||
DataType::UInt32 => Ok(Value::int(downcast!(UInt32Array) as i64, span)),
|
||||
DataType::UInt64 => Ok(Value::int(downcast!(UInt64Array) as i64, span)),
|
||||
DataType::Int8 => Ok(Value::int(downcast!(Int8Array) as i64, span)),
|
||||
DataType::Int16 => Ok(Value::int(downcast!(Int16Array) as i64, span)),
|
||||
DataType::Int32 => Ok(Value::int(downcast!(Int32Array) as i64, span)),
|
||||
DataType::Int64 => Ok(Value::int(downcast!(Int64Array), span)),
|
||||
DataType::Float32 => Ok(Value::float(downcast!(Float32Array) as f64, span)),
|
||||
DataType::Float64 => Ok(Value::float(downcast!(Float64Array), span)),
|
||||
// DataType::Decimal(_, _) => {}
|
||||
DataType::Utf8 => Ok(Value::string(downcast!(LargeStringArray).to_string(), span)),
|
||||
DataType::Binary => Ok(Value::binary(downcast!(LargeBinaryArray).to_owned(), span)),
|
||||
DataType::Date => {
|
||||
let date = downcast!(Int32Array);
|
||||
let nanos = nanos_per_day(date);
|
||||
datetime_from_epoch_nanos(nanos, &None, span)
|
||||
.map(|datetime| Value::date(datetime, span))
|
||||
}
|
||||
DataType::Datetime(time_unit, tz) => {
|
||||
let nanos = nanos_from_timeunit(downcast!(Int64Array), *time_unit);
|
||||
datetime_from_epoch_nanos(nanos, tz, span)
|
||||
.map(|datetime| Value::date(datetime, span))
|
||||
}
|
||||
// DataType::Duration(_) => {}
|
||||
DataType::Time => {
|
||||
let t = downcast!(Int64Array);
|
||||
time_from_midnight(t, span)
|
||||
}
|
||||
DataType::List(dt) => {
|
||||
let v: ArrayRef = downcast!(LargeListArray);
|
||||
let values_result = if dt.is_primitive() {
|
||||
let s = Series::from_chunks_and_dtype_unchecked("", vec![v], dt);
|
||||
series_to_values(&s, None, None, span)
|
||||
} else {
|
||||
let s = Series::from_chunks_and_dtype_unchecked("", vec![v], &dt.to_physical())
|
||||
.cast_unchecked(dt)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating Value from polars LargeListArray".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
series_to_values(&s, None, None, span)
|
||||
};
|
||||
values_result.map(|values| Value::list(values, span))
|
||||
}
|
||||
DataType::Null => Ok(Value::nothing(span)),
|
||||
DataType::Struct(fields) => {
|
||||
let arr = &*(arr as *const dyn Array as *const StructArray);
|
||||
let vals: Result<Vec<Value>, ShellError> = arr
|
||||
.values()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(pos, v)| {
|
||||
let f = &fields[pos];
|
||||
arr_to_value(&f.dtype, &**v, 0, span)
|
||||
})
|
||||
.collect();
|
||||
let cols = fields.iter().map(|f| f.name().to_string()).collect();
|
||||
Ok(Value::record(Record { cols, vals: vals? }, span))
|
||||
}
|
||||
DataType::Unknown => Ok(Value::nothing(span)),
|
||||
_ => Err(ShellError::CantConvert {
|
||||
to_type: dt.to_string(),
|
||||
from_type: "polars array".to_string(),
|
||||
span,
|
||||
help: Some(format!(
|
||||
"Could not convert polars array of type {:?} to value",
|
||||
dt
|
||||
)),
|
||||
}),
|
||||
}
|
||||
e => Err(ShellError::GenericError {
|
||||
error: "Error creating Value".into(),
|
||||
msg: "".to_string(),
|
||||
span: None,
|
||||
help: Some(format!("Value not supported in nushell: {e}")),
|
||||
inner: Vec::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1157,15 +1020,15 @@ fn datetime_from_epoch_nanos(
|
||||
span: Span,
|
||||
) -> Result<DateTime<FixedOffset>, ShellError> {
|
||||
let tz: Tz = if let Some(polars_tz) = timezone {
|
||||
polars_tz.parse::<Tz>().map_err(|_| {
|
||||
ShellError::GenericError(
|
||||
format!("Could not parse polars timezone: {polars_tz}"),
|
||||
"".to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
vec![],
|
||||
)
|
||||
})?
|
||||
polars_tz
|
||||
.parse::<Tz>()
|
||||
.map_err(|_| ShellError::GenericError {
|
||||
error: format!("Could not parse polars timezone: {polars_tz}"),
|
||||
msg: "".to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
} else {
|
||||
Tz::UTC
|
||||
};
|
||||
@ -1196,9 +1059,9 @@ fn time_from_midnight(nanos: i64, span: Span) -> Result<Value, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use indexmap::indexmap;
|
||||
use polars::export::arrow::array::{ListArray, NullArray, PrimitiveArray};
|
||||
use polars::export::arrow::buffer::Buffer;
|
||||
use polars::export::arrow::array::{BooleanArray, PrimitiveArray};
|
||||
use polars::prelude::Field;
|
||||
use polars_io::prelude::StructArray;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -1415,195 +1278,4 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arr_to_value() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let test_bool_arr = BooleanArray::from([Some(true)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Boolean, &test_bool_arr, 0, Span::test_data())?,
|
||||
Value::bool(true, Span::test_data())
|
||||
);
|
||||
|
||||
let test_uint8_arr = PrimitiveArray::from([Some(9_u8)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::UInt8, &test_uint8_arr, 0, Span::test_data())?,
|
||||
Value::int(9, Span::test_data())
|
||||
);
|
||||
|
||||
let test_uint16_arr = PrimitiveArray::from([Some(3223_u16)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::UInt16, &test_uint16_arr, 0, Span::test_data())?,
|
||||
Value::int(3223, Span::test_data())
|
||||
);
|
||||
|
||||
let test_uint32_arr = PrimitiveArray::from([Some(33_u32)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::UInt32, &test_uint32_arr, 0, Span::test_data())?,
|
||||
Value::int(33, Span::test_data())
|
||||
);
|
||||
|
||||
let test_uint64_arr = PrimitiveArray::from([Some(33_3232_u64)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::UInt64, &test_uint64_arr, 0, Span::test_data())?,
|
||||
Value::int(33_3232, Span::test_data())
|
||||
);
|
||||
|
||||
let test_int8_arr = PrimitiveArray::from([Some(9_i8)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Int8, &test_int8_arr, 0, Span::test_data())?,
|
||||
Value::int(9, Span::test_data())
|
||||
);
|
||||
|
||||
let test_int16_arr = PrimitiveArray::from([Some(3223_i16)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Int16, &test_int16_arr, 0, Span::test_data())?,
|
||||
Value::int(3223, Span::test_data())
|
||||
);
|
||||
|
||||
let test_int32_arr = PrimitiveArray::from([Some(33_i32)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Int32, &test_int32_arr, 0, Span::test_data())?,
|
||||
Value::int(33, Span::test_data())
|
||||
);
|
||||
|
||||
let test_int64_arr = PrimitiveArray::from([Some(33_3232_i64)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Int64, &test_int64_arr, 0, Span::test_data())?,
|
||||
Value::int(33_3232, Span::test_data())
|
||||
);
|
||||
|
||||
let test_float32_arr = PrimitiveArray::from([Some(33.32_f32)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Float32, &test_float32_arr, 0, Span::test_data())?,
|
||||
Value::float(33.32_f32 as f64, Span::test_data())
|
||||
);
|
||||
|
||||
let test_float64_arr = PrimitiveArray::from([Some(33_3232.999_f64)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Float64, &test_float64_arr, 0, Span::test_data())?,
|
||||
Value::float(33_3232.999, Span::test_data())
|
||||
);
|
||||
|
||||
let test_str = "hello world";
|
||||
let test_str_arr = LargeStringArray::from(vec![Some(test_str.to_string())]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Utf8, &test_str_arr, 0, Span::test_data())?,
|
||||
Value::string(test_str.to_string(), Span::test_data())
|
||||
);
|
||||
|
||||
let test_bin = b"asdlfkjadsf";
|
||||
let test_bin_arr = LargeBinaryArray::from(vec![Some(test_bin.to_vec())]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Binary, &test_bin_arr, 0, Span::test_data())?,
|
||||
Value::binary(test_bin.to_vec(), Span::test_data())
|
||||
);
|
||||
|
||||
let test_days = 10_957_i32;
|
||||
let comparison_date = Utc
|
||||
.with_ymd_and_hms(2000, 1, 1, 0, 0, 0)
|
||||
.unwrap()
|
||||
.fixed_offset();
|
||||
let test_date_arr = PrimitiveArray::from([Some(test_days)]);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Date, &test_date_arr, 0, Span::test_data())?,
|
||||
Value::date(comparison_date, Span::test_data())
|
||||
);
|
||||
|
||||
let test_dt_nanos = 1_357_488_900_000_000_000_i64;
|
||||
let test_dt_arr = PrimitiveArray::from([Some(test_dt_nanos)]);
|
||||
let test_dt = Utc.timestamp_nanos(test_dt_nanos).fixed_offset();
|
||||
assert_eq!(
|
||||
arr_to_value(
|
||||
&DataType::Datetime(TimeUnit::Nanoseconds, Some("UTC".to_owned())),
|
||||
&test_dt_arr,
|
||||
0,
|
||||
Span::test_data()
|
||||
)?,
|
||||
Value::date(test_dt, Span::test_data())
|
||||
);
|
||||
|
||||
let test_time_nanos = 54_000_000_000_000_i64;
|
||||
let test_dt_arr = PrimitiveArray::from([Some(test_time_nanos)]);
|
||||
let test_time = DateTime::<FixedOffset>::from_naive_utc_and_offset(
|
||||
Utc::now()
|
||||
.date_naive()
|
||||
.and_time(NaiveTime::from_hms_opt(15, 00, 00).unwrap()),
|
||||
FixedOffset::east_opt(0).unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
arr_to_value(&DataType::Time, &test_dt_arr, 0, Span::test_data())?,
|
||||
Value::date(test_time, Span::test_data())
|
||||
);
|
||||
|
||||
let values = Buffer::from(vec![1, 2, 3]);
|
||||
let values = PrimitiveArray::<i64>::new(DataType::Int64.to_arrow(), values, None);
|
||||
let data_type = ListArray::<i64>::default_datatype(DataType::Int64.to_arrow());
|
||||
let array = ListArray::<i64>::new(
|
||||
data_type,
|
||||
vec![0, 3].try_into().unwrap(),
|
||||
Box::new(values),
|
||||
None,
|
||||
);
|
||||
let comparison_list_series = Value::list(
|
||||
vec![
|
||||
Value::int(1, Span::test_data()),
|
||||
Value::int(2, Span::test_data()),
|
||||
Value::int(3, Span::test_data()),
|
||||
],
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(
|
||||
arr_to_value(
|
||||
&DataType::List(Box::new(DataType::Int64)),
|
||||
&array,
|
||||
0,
|
||||
Span::test_data()
|
||||
)?,
|
||||
comparison_list_series
|
||||
);
|
||||
|
||||
let field_name_0 = "num_field";
|
||||
let field_name_1 = "bool_field";
|
||||
let fields = vec![
|
||||
Field::new(field_name_0, DataType::Int32),
|
||||
Field::new(field_name_1, DataType::Boolean),
|
||||
];
|
||||
let test_int_arr = PrimitiveArray::from([Some(1_i32)]);
|
||||
let test_struct_arr = StructArray::new(
|
||||
DataType::Struct(fields.clone()).to_arrow(),
|
||||
vec![Box::new(test_int_arr), Box::new(test_bool_arr)],
|
||||
None,
|
||||
);
|
||||
let comparison_owned_record = Value::record(
|
||||
Record {
|
||||
cols: vec![field_name_0.to_owned(), field_name_1.to_owned()],
|
||||
vals: vec![
|
||||
Value::int(1, Span::test_data()),
|
||||
Value::bool(true, Span::test_data()),
|
||||
],
|
||||
},
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(
|
||||
arr_to_value(
|
||||
&DataType::Struct(fields),
|
||||
&test_struct_arr,
|
||||
0,
|
||||
Span::test_data(),
|
||||
)?,
|
||||
comparison_owned_record
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
arr_to_value(
|
||||
&DataType::Null,
|
||||
&NullArray::new(DataType::Null.to_arrow(), 0),
|
||||
0,
|
||||
Span::test_data()
|
||||
)?,
|
||||
Value::nothing(Span::test_data())
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ pub use operations::Axis;
|
||||
use indexmap::map::IndexMap;
|
||||
use nu_protocol::{did_you_mean, PipelineData, Record, ShellError, Span, Value};
|
||||
use polars::prelude::{DataFrame, DataType, IntoLazy, LazyFrame, PolarsObject, Series};
|
||||
use polars_arrow::util::total_ord::TotalEq;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cmp::Ordering, fmt::Display, hash::Hasher};
|
||||
|
||||
@ -61,6 +62,12 @@ impl std::hash::Hash for DataFrameValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl TotalEq for DataFrameValue {
|
||||
fn tot_eq(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PolarsObject for DataFrameValue {
|
||||
fn type_name() -> &'static str {
|
||||
"object"
|
||||
@ -124,13 +131,13 @@ impl NuDataFrame {
|
||||
pub fn series_to_value(series: Series, span: Span) -> Result<Value, ShellError> {
|
||||
match DataFrame::new(vec![series]) {
|
||||
Ok(dataframe) => Ok(NuDataFrame::dataframe_into_value(dataframe, span)),
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Error creating dataframe".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(ShellError::GenericError {
|
||||
error: "Error creating dataframe".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,14 +174,12 @@ impl NuDataFrame {
|
||||
}
|
||||
|
||||
pub fn try_from_series(columns: Vec<Series>, span: Span) -> Result<Self, ShellError> {
|
||||
let dataframe = DataFrame::new(columns).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating dataframe".into(),
|
||||
format!("Unable to create DataFrame: {e}"),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let dataframe = DataFrame::new(columns).map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating dataframe".into(),
|
||||
msg: format!("Unable to create DataFrame: {e}"),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
Ok(Self::new(false, dataframe))
|
||||
@ -288,17 +293,18 @@ impl NuDataFrame {
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let option = did_you_mean(&possibilities, column).unwrap_or_else(|| column.to_string());
|
||||
ShellError::DidYouMean(option, span)
|
||||
ShellError::DidYouMean {
|
||||
suggestion: option,
|
||||
span,
|
||||
}
|
||||
})?;
|
||||
|
||||
let df = DataFrame::new(vec![s.clone()]).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating dataframe".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let df = DataFrame::new(vec![s.clone()]).map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating dataframe".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
@ -313,19 +319,19 @@ impl NuDataFrame {
|
||||
|
||||
pub fn as_series(&self, span: Span) -> Result<Series, ShellError> {
|
||||
if !self.is_series() {
|
||||
return Err(ShellError::GenericError(
|
||||
"Error using as series".into(),
|
||||
"dataframe has more than one column".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Error using as series".into(),
|
||||
msg: "dataframe has more than one column".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
let series = self
|
||||
.df
|
||||
.get_columns()
|
||||
.get(0)
|
||||
.first()
|
||||
.expect("We have already checked that the width is 1");
|
||||
|
||||
Ok(series.clone())
|
||||
|
@ -24,10 +24,10 @@ impl NuDataFrame {
|
||||
match right {
|
||||
Value::CustomValue { val: rhs, .. } => {
|
||||
let rhs = rhs.as_any().downcast_ref::<NuDataFrame>().ok_or_else(|| {
|
||||
ShellError::DowncastNotPossible(
|
||||
"Unable to create dataframe".to_string(),
|
||||
rhs_span,
|
||||
)
|
||||
ShellError::DowncastNotPossible {
|
||||
msg: "Unable to create dataframe".to_string(),
|
||||
span: rhs_span,
|
||||
}
|
||||
})?;
|
||||
|
||||
match (self.is_series(), rhs.is_series()) {
|
||||
@ -135,14 +135,12 @@ impl NuDataFrame {
|
||||
})
|
||||
.collect::<Vec<Series>>();
|
||||
|
||||
let df_new = DataFrame::new(new_cols).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error creating dataframe".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let df_new = DataFrame::new(new_cols).map_err(|e| ShellError::GenericError {
|
||||
error: "Error creating dataframe".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
Ok(NuDataFrame::new(false, df_new))
|
||||
@ -183,26 +181,24 @@ impl NuDataFrame {
|
||||
match res {
|
||||
Ok(s) => Ok(s.clone()),
|
||||
Err(e) => Err({
|
||||
ShellError::GenericError(
|
||||
"Error appending dataframe".into(),
|
||||
format!("Unable to append: {e}"),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
ShellError::GenericError {
|
||||
error: "Error appending dataframe".into(),
|
||||
msg: format!("Unable to append: {e}"),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}
|
||||
}),
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<Series>, ShellError>>()?;
|
||||
|
||||
let df_new = DataFrame::new(new_cols).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error appending dataframe".into(),
|
||||
format!("Unable to append dataframes: {e}"),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
let df_new = DataFrame::new(new_cols).map_err(|e| ShellError::GenericError {
|
||||
error: "Error appending dataframe".into(),
|
||||
msg: format!("Unable to append dataframes: {e}"),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
Ok(NuDataFrame::new(false, df_new))
|
||||
|
@ -57,7 +57,10 @@ fn compute_with_value(
|
||||
match right {
|
||||
Value::CustomValue { val: rhs, .. } => {
|
||||
let rhs = rhs.as_any().downcast_ref::<NuExpression>().ok_or_else(|| {
|
||||
ShellError::DowncastNotPossible("Unable to create expression".to_string(), rhs_span)
|
||||
ShellError::DowncastNotPossible {
|
||||
msg: "Unable to create expression".into(),
|
||||
span: rhs_span,
|
||||
}
|
||||
})?;
|
||||
|
||||
match rhs.as_ref() {
|
||||
|
@ -299,7 +299,11 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Take { expr, idx } => Ok(Value::record(
|
||||
Expr::Gather {
|
||||
expr,
|
||||
idx,
|
||||
returns_scalar: _,
|
||||
} => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"idx" => expr_to_value(idx.as_ref(), span)?,
|
||||
@ -401,7 +405,6 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
|
||||
Expr::Window {
|
||||
function,
|
||||
partition_by,
|
||||
order_by,
|
||||
options,
|
||||
} => {
|
||||
let partition_by: Result<Vec<Value>, ShellError> = partition_by
|
||||
@ -409,22 +412,21 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
|
||||
.map(|e| expr_to_value(e, span))
|
||||
.collect();
|
||||
|
||||
let order_by = order_by
|
||||
.as_ref()
|
||||
.map(|e| expr_to_value(e.as_ref(), span))
|
||||
.transpose()?
|
||||
.unwrap_or_else(|| Value::nothing(span));
|
||||
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"function" => expr_to_value(function, span)?,
|
||||
"partition_by" => Value::list(partition_by?, span),
|
||||
"order_by" => order_by,
|
||||
"options" => Value::string(format!("{options:?}"), span),
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
Expr::SubPlan(_, _) => Err(ShellError::UnsupportedInput {
|
||||
msg: "Expressions of type SubPlan are not yet supported".to_string(),
|
||||
input: format!("Expression is {expr:?}"),
|
||||
msg_span: span,
|
||||
input_span: Span::unknown(),
|
||||
}),
|
||||
// the parameter polars_plan::dsl::selector::Selector is not publicly exposed.
|
||||
// I am not sure what we can meaningfully do with this at this time.
|
||||
Expr::Selector(_) => Err(ShellError::UnsupportedInput {
|
||||
|
@ -104,14 +104,12 @@ impl NuLazyFrame {
|
||||
self.lazy
|
||||
.expect("No empty lazy for collect")
|
||||
.collect()
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error collecting lazy frame".to_string(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error collecting lazy frame".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.map(|df| NuDataFrame {
|
||||
df,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user