Skip to content

Commit

Permalink
cli: fix issue when sorting by run_number or human_readable size
Browse files Browse the repository at this point in the history
  • Loading branch information
giuseppe-steduto committed Aug 28, 2023
1 parent 1f45b1b commit f1fbf1a
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
#
# This file is part of REANA.
# Copyright (C) 2022 CERN.
# Copyright (C) 2022, 2023 CERN.
#
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down
6 changes: 4 additions & 2 deletions cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of REANA.
Copyright (C) 2022 CERN.
Copyright (C) 2022, 2023 CERN.
REANA is free software; you can redistribute it and/or modify it
under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -226,6 +226,7 @@ func displayListPayload(
jsonOutput, humanReadable bool,
) error {
var df dataframe.DataFrame
readableToRaw := make(map[string]int64)
for _, col := range header {
colSeries := buildListSeries(col, humanReadable)
for _, workflow := range p.Items {
Expand All @@ -240,6 +241,7 @@ func displayListPayload(
case "size":
if humanReadable {
value = workflow.Size.HumanReadable
readableToRaw[value.(string)] = workflow.Size.Raw
} else {
value = int(workflow.Size.Raw)
}
Expand Down Expand Up @@ -285,7 +287,7 @@ func displayListPayload(
df = df.CBind(dataframe.New(colSeries))
}

df, err := formatter.SortDataFrame(df, sortColumn, true)
df, err := formatter.SortDataFrame(df, sortColumn, true, readableToRaw, humanReadable)
if err != nil {
cmd.PrintErrf("Warning: sort operation was aborted, %s\n", err)
}
Expand Down
44 changes: 42 additions & 2 deletions pkg/formatter/formatter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of REANA.
Copyright (C) 2022 CERN.
Copyright (C) 2022, 2023 CERN.
REANA is free software; you can redistribute it and/or modify it
under the terms of the MIT License; see LICENSE file for more details.
Expand All @@ -12,6 +12,7 @@ package formatter
import (
"fmt"
"reanahub/reana-client-go/pkg/validator"
"strconv"
"strings"

"github.com/go-gota/gota/dataframe"
Expand Down Expand Up @@ -77,13 +78,52 @@ func SortDataFrame(
df dataframe.DataFrame,
sortColumn string,
reverse bool,
readableToRaw map[string]int64,
humanReadable bool,
) (dataframe.DataFrame, error) {
sortColumn = strings.ToLower(sortColumn)
if !slices.Contains(df.Names(), sortColumn) {
return df, fmt.Errorf("column '%s' does not exist", sortColumn)
}

return df.Arrange(dataframe.Order{Colname: sortColumn, Reverse: reverse}), nil
if sortColumn == "run_number" {
runNumbers := df.Col("run_number").Records()

//Convert run_number string into integers and put those in a new
// temporary dataframe column, which will be used for sorting.
var sortableRunNumber []int
for _, v := range runNumbers {
parts := strings.Split(v, ".")
major, _ := strconv.Atoi(parts[0])
var minor int
if len(parts) > 1 {
minor, _ = strconv.Atoi(parts[1])
}
sortableVersion := major*1000 + minor
sortableRunNumber = append(sortableRunNumber, sortableVersion)
}

// Sort dataframe using sortable "sortable_run_number" column
df = df.Mutate(series.New(sortableRunNumber, series.Int, "sortable_run_number"))
sortColumn = "sortable_run_number"
}

if sortColumn == "size" && humanReadable {
var sortableSize []int
for _, v := range df.Col("size").Records() {
sortableSize = append(sortableSize, int(readableToRaw[v]))
}
df = df.Mutate(series.New(sortableSize, series.Int, "sortable_size"))
sortColumn = "sortable_size"
}

sortedDF := df.Arrange(dataframe.Order{Colname: sortColumn, Reverse: reverse})
if sortColumn == "sortable_run_number" || sortColumn == "sortable_size" {
// Remove temporary column used for sorting
sortedDF = sortedDF.Drop(sortColumn)
}

return sortedDF, nil
}

// DataFrameToStringData converts a given dataFrame to a 2D slice of strings.
Expand Down
75 changes: 58 additions & 17 deletions pkg/formatter/formatter_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of REANA.
Copyright (C) 2022 CERN.
Copyright (C) 2022, 2023 CERN.
REANA is free software; you can redistribute it and/or modify it
under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -180,16 +180,21 @@ func TestFormatDataFrame(t *testing.T) {
func TestSortDataFrame(t *testing.T) {
tests := map[string]struct {
df dataframe.DataFrame
expected dataframe.DataFrame
sortColumn string
reverse bool
readToRaw map[string]int64
humanRead bool
wantError bool
}{
"sort ascending": {
df: dataframe.New(series.New([]string{"b", "a", "c"}, series.String, "col1")),
expected: dataframe.New(series.New([]string{"a", "b", "c"}, series.String, "col1")),
sortColumn: "col1",
},
"sort descending": {
df: dataframe.New(series.New([]string{"b", "a", "c"}, series.String, "col1")),
expected: dataframe.New(series.New([]string{"c", "b", "a"}, series.String, "col1")),
sortColumn: "col1",
reverse: true,
},
Expand All @@ -198,15 +203,54 @@ func TestSortDataFrame(t *testing.T) {
series.New([]string{"b", "a", "c"}, series.String, "col1"),
series.New([]int{2, 1, 3}, series.Int, "col2"),
),
expected: dataframe.New(series.New([]int{1, 2, 3}, series.Int, "col2")),
sortColumn: "col2",
},
"sort float": {
df: dataframe.New(series.New([]float64{2.0, 1.0, 3.0}, series.Float, "col1")),
expected: dataframe.New(series.New([]float64{1.0, 2.0, 3.0}, series.Float, "col1")),
sortColumn: "col1",
},
"lowercase sort columns": {
df: dataframe.New(series.New([]string{"b", "a", "c"}, series.String, "col1")),
sortColumn: "col1",
"sort run_numbers": {
df: dataframe.New(
series.New(
[]string{"1", "2.2", "10", "9.1", "1.15", "2.10"},
series.String,
"run_number",
),
),
expected: dataframe.New(
series.New(
[]string{"1", "1.15", "2.2", "2.10", "9.1", "10"},
series.String,
"run_number",
),
),
sortColumn: "run_number",
},
"sort size human_readable": {
df: dataframe.New(
series.New(
[]string{"255 KiB", "1.92 MiB", "192 KiB", "1.1 GiB"},
series.String,
"size",
),
),
expected: dataframe.New(
series.New(
[]string{"192 KiB", "255 KiB", "1.92 MiB", "1.1 GiB"},
series.String,
"size",
),
),
sortColumn: "size",
readToRaw: map[string]int64{
"255 KiB": 261120,
"1.92 MiB": 2013265,
"192 KiB": 196608,
"1.1 GiB": 1181116006,
},
humanRead: true,
},
"non-existent column": {
df: dataframe.New(series.New([]string{"b", "a", "c"}, series.String, "col1")),
Expand All @@ -216,7 +260,13 @@ func TestSortDataFrame(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
df, err := SortDataFrame(test.df, test.sortColumn, test.reverse)
df, err := SortDataFrame(
test.df,
test.sortColumn,
test.reverse,
test.readToRaw,
test.humanRead,
)
if test.wantError {
if err == nil {
t.Errorf("Expected error, got '%s'", err.Error())
Expand All @@ -227,18 +277,9 @@ func TestSortDataFrame(t *testing.T) {
}

col := df.Col(test.sortColumn)
for i := 0; i < col.Len()-1; i++ {
if test.reverse {
if col.Elem(i + 1).Greater(col.Elem(i)) {
t.Errorf("Expected column '%s' to be sorted in descending order, got %v",
test.sortColumn, col.Records())
}
} else {
if col.Elem(i + 1).Less(col.Elem(i)) {
t.Errorf("Expected column '%s' to be sorted in ascending order, got %v",
test.sortColumn, col.Records())
}
}
expectedCol := test.expected.Col(test.sortColumn)
if !reflect.DeepEqual(col, expectedCol) {
t.Errorf("The given dataframe and the expected one do not match!")
}
}
})
Expand Down

0 comments on commit f1fbf1a

Please sign in to comment.