From 10f5c4ffb7fc9be3f2426e1099857af3d89158e8 Mon Sep 17 00:00:00 2001 From: LeandroC89 Date: Sat, 27 Aug 2022 11:39:26 +0100 Subject: [PATCH 1/6] - Added test for new sheet implementation Signed-off-by: LeandroC89 --- .gitignore | 1 + .../org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/.gitignore b/.gitignore index 43306037d2..e78af1c176 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .gradle build .ipynb_checkpoints +/dataframe-excel/src/test/resources/generated_wb.xlsx diff --git a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt index 102f637cbe..1cda23b947 100644 --- a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt +++ b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt @@ -109,4 +109,18 @@ class XlsxTest { DataFrame.readExcel(testResource("xlsx6.xlsx"), skipRows = 4) } } + + @Test + fun `write to new sheet when erase is false`() { + val df = DataFrame.readExcel(testResource("sample4.xls"), skipRows = 6, rowsCount = 1) + val fileLoc = testResource("generated_wb.xlsx").toURI().toString().removeRange(0, 6) +println(fileLoc) + df.writeExcel(fileLoc, sheetName = "TestSheet1") + df.writeExcel(fileLoc, sheetName = "TestSheet2") + + val testSheet1Df = DataFrame.readExcel(testResource("generated_wb.xlsx"), sheetName = "TestSheet1") + val testSheet2Df = DataFrame.readExcel(testResource("generated_wb.xlsx"), sheetName = "TestSheet2") + + testSheet1Df.columnNames() shouldBe testSheet2Df.columnNames() + } } From 27c63966088a40df2cdaf2ea87276621ccf0a522 Mon Sep 17 00:00:00 2001 From: LeandroC89 Date: Sat, 27 Aug 2022 11:40:05 +0100 Subject: [PATCH 2/6] - Removed unnecessary logging from new sheet test Signed-off-by: LeandroC89 --- .../test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt index 1cda23b947..53e704283a 100644 --- a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt +++ b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt @@ -114,7 +114,7 @@ class XlsxTest { fun `write to new sheet when erase is false`() { val df = DataFrame.readExcel(testResource("sample4.xls"), skipRows = 6, rowsCount = 1) val fileLoc = testResource("generated_wb.xlsx").toURI().toString().removeRange(0, 6) -println(fileLoc) + df.writeExcel(fileLoc, sheetName = "TestSheet1") df.writeExcel(fileLoc, sheetName = "TestSheet2") From a5f8a1b6f436b44abaa7f4c19294374249b6ed17 Mon Sep 17 00:00:00 2001 From: LeandroC89 Date: Sun, 28 Aug 2022 02:09:43 +0100 Subject: [PATCH 3/6] - Added addSheet functionality (keepFile parameter) - Updated WorkBook factory as it was previously incompatible with reusing existing workbook - Revised test use generated random data Signed-off-by: LeandroC89 --- .../jetbrains/kotlinx/dataframe/io/xlsx.kt | 48 +++++++++---------- .../kotlinx/dataframe/io/XlsxTest.kt | 7 +-- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/dataframe-excel/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/xlsx.kt b/dataframe-excel/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/xlsx.kt index 8b4a896fc0..0122b9b1bc 100644 --- a/dataframe-excel/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/xlsx.kt +++ b/dataframe-excel/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/xlsx.kt @@ -4,23 +4,12 @@ import kotlinx.datetime.toJavaLocalDate import kotlinx.datetime.toJavaLocalDateTime import kotlinx.datetime.toKotlinLocalDateTime import org.apache.poi.hssf.usermodel.HSSFWorkbook -import org.apache.poi.ss.usermodel.Cell -import org.apache.poi.ss.usermodel.CellType -import org.apache.poi.ss.usermodel.DateUtil -import org.apache.poi.ss.usermodel.RichTextString -import org.apache.poi.ss.usermodel.Row -import org.apache.poi.ss.usermodel.Sheet -import org.apache.poi.ss.usermodel.Workbook -import org.apache.poi.ss.usermodel.WorkbookFactory +import org.apache.poi.ss.usermodel.* import org.apache.poi.ss.util.CellReference import org.apache.poi.util.LocaleUtil import org.apache.poi.util.LocaleUtil.getUserTimeZone import org.apache.poi.xssf.usermodel.XSSFWorkbook -import org.jetbrains.kotlinx.dataframe.AnyFrame -import org.jetbrains.kotlinx.dataframe.AnyRow -import org.jetbrains.kotlinx.dataframe.ColumnsSelector -import org.jetbrains.kotlinx.dataframe.DataColumn -import org.jetbrains.kotlinx.dataframe.DataFrame +import org.jetbrains.kotlinx.dataframe.* import org.jetbrains.kotlinx.dataframe.api.dataFrameOf import org.jetbrains.kotlinx.dataframe.api.forEach import org.jetbrains.kotlinx.dataframe.api.select @@ -32,8 +21,7 @@ import java.io.OutputStream import java.net.URL import java.time.LocalDate import java.time.LocalDateTime -import java.util.Calendar -import java.util.Date +import java.util.* public class Excel : SupportedFormat { override fun readDataFrame(stream: InputStream, header: List): AnyFrame = DataFrame.readExcel(stream) @@ -216,9 +204,10 @@ public fun DataFrame.writeExcel( columnsSelector: ColumnsSelector = { all() }, sheetName: String? = null, writeHeader: Boolean = true, - workBookType: WorkBookType = WorkBookType.XLSX + workBookType: WorkBookType = WorkBookType.XLSX, + keepFile: Boolean = false, ) { - return writeExcel(File(path), columnsSelector, sheetName, writeHeader, workBookType) + return writeExcel(File(path), columnsSelector, sheetName, writeHeader, workBookType, keepFile) } public enum class WorkBookType { @@ -230,12 +219,23 @@ public fun DataFrame.writeExcel( columnsSelector: ColumnsSelector = { all() }, sheetName: String? = null, writeHeader: Boolean = true, - workBookType: WorkBookType = WorkBookType.XLSX + workBookType: WorkBookType = WorkBookType.XLSX, + keepFile: Boolean = false, ) { - val factory = when (workBookType) { - WorkBookType.XLS -> { { HSSFWorkbook() } } - WorkBookType.XLSX -> { { XSSFWorkbook() } } - } + + val factory = + if (keepFile){ + when (workBookType) { + WorkBookType.XLS -> HSSFWorkbook(file.inputStream()) + WorkBookType.XLSX -> XSSFWorkbook(file.inputStream()) + } + } + else { + when (workBookType) { + WorkBookType.XLS -> HSSFWorkbook() + WorkBookType.XLSX -> XSSFWorkbook() + } + } return file.outputStream().use { writeExcel(it, columnsSelector, sheetName, writeHeader, factory) } @@ -246,9 +246,9 @@ public fun DataFrame.writeExcel( columnsSelector: ColumnsSelector = { all() }, sheetName: String? = null, writeHeader: Boolean = true, - factory: () -> Workbook + factory: Workbook ) { - val wb: Workbook = factory() + val wb: Workbook = factory writeExcel(wb, columnsSelector, sheetName, writeHeader) wb.write(outputStream) wb.close() diff --git a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt index 53e704283a..c34da89138 100644 --- a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt +++ b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt @@ -111,12 +111,13 @@ class XlsxTest { } @Test - fun `write to new sheet when erase is false`() { - val df = DataFrame.readExcel(testResource("sample4.xls"), skipRows = 6, rowsCount = 1) + fun `write to new sheet when keepFile is true`() { + val names = (1..5).map { "column$it" } + val df = dataFrameOf(names).randomDouble(7) val fileLoc = testResource("generated_wb.xlsx").toURI().toString().removeRange(0, 6) df.writeExcel(fileLoc, sheetName = "TestSheet1") - df.writeExcel(fileLoc, sheetName = "TestSheet2") + df.writeExcel(fileLoc, sheetName = "TestSheet2", keepFile = true) val testSheet1Df = DataFrame.readExcel(testResource("generated_wb.xlsx"), sheetName = "TestSheet1") val testSheet2Df = DataFrame.readExcel(testResource("generated_wb.xlsx"), sheetName = "TestSheet2") From 679d7ffdb0e1666f217244bff3df5f778d4b04c6 Mon Sep 17 00:00:00 2001 From: LeandroC89 Date: Mon, 12 Sep 2022 01:10:29 +0100 Subject: [PATCH 4/6] - Added new function in org.jetbrains.kotlinx.dataframe.samples.api.Write for keepFile functionality - Added example of keepFile use in writeExcel to write.md Signed-off-by: LeandroC89 --- docs/StardustDocs/topics/write.md | 15 +++++++++++++++ .../kotlinx/dataframe/samples/api/Write.kt | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/docs/StardustDocs/topics/write.md b/docs/StardustDocs/topics/write.md index 72b540394c..81a7a04f4e 100644 --- a/docs/StardustDocs/topics/write.md +++ b/docs/StardustDocs/topics/write.md @@ -116,3 +116,18 @@ wb.close() ``` + +Add new sheets without using Apache POI directly by using a parameter to keep using the same file if it already exists + + + +```kotlin +// Create a new Excel workbook with a single sheet called "allPersons", replacing the file if it already exists -> Current sheets: allPersons +val allPersonsSheet = df.writeExcel(file, sheetName = "allPersons") +// Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons +val happyPersonsSheet = df.filter { person -> person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "happyPersons", keepFile = true) +// Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons, unhappyPersons +val unhappyPersonsSheet = df.filter { person -> !person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "unhappyPersons", keepFile = true) +``` + + diff --git a/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt b/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt index 6fc2370775..803f42b7f0 100644 --- a/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt +++ b/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt @@ -121,6 +121,20 @@ class Write : TestBase() { } } + @Test + fun writeXlsWithMultipleSheets() { + useTempFile { file -> + // SampleStart + // Create a new Excel workbook with a single sheet called "allPersons", replacing the file if it already exists -> Current sheets: allPersons + val allPersonsSheet = df.writeExcel(file, sheetName = "allPersons") + // Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons + val happyPersonsSheet = df.filter { person -> person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "happyPersons", keepFile = true) + // Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons, unhappyPersons + val unhappyPersonsSheet = df.filter { person -> !person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "unhappyPersons", keepFile = true) + // SampleEnd + } + } + companion object { private fun String.rejoinWithSystemLineSeparator() = rejoinWithLineSeparator(System.lineSeparator()) From 9182ad69abf2ae582c6e381d340fa7ab929de346 Mon Sep 17 00:00:00 2001 From: LeandroC89 Date: Mon, 12 Sep 2022 08:40:58 +0100 Subject: [PATCH 5/6] - Fixed variable use in added function for documentation Signed-off-by: LeandroC89 --- docs/StardustDocs/topics/write.md | 6 +++--- .../org/jetbrains/kotlinx/dataframe/samples/api/Write.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/StardustDocs/topics/write.md b/docs/StardustDocs/topics/write.md index 81a7a04f4e..bb192b6c17 100644 --- a/docs/StardustDocs/topics/write.md +++ b/docs/StardustDocs/topics/write.md @@ -123,11 +123,11 @@ Add new sheets without using Apache POI directly by using a parameter to keep us ```kotlin // Create a new Excel workbook with a single sheet called "allPersons", replacing the file if it already exists -> Current sheets: allPersons -val allPersonsSheet = df.writeExcel(file, sheetName = "allPersons") +df.writeExcel(file, sheetName = "allPersons") // Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons -val happyPersonsSheet = df.filter { person -> person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "happyPersons", keepFile = true) +df.filter { person -> person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "happyPersons", keepFile = true) // Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons, unhappyPersons -val unhappyPersonsSheet = df.filter { person -> !person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "unhappyPersons", keepFile = true) +df.filter { person -> !person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "unhappyPersons", keepFile = true) ``` diff --git a/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt b/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt index 803f42b7f0..a2338688d3 100644 --- a/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt +++ b/tests/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Write.kt @@ -126,11 +126,11 @@ class Write : TestBase() { useTempFile { file -> // SampleStart // Create a new Excel workbook with a single sheet called "allPersons", replacing the file if it already exists -> Current sheets: allPersons - val allPersonsSheet = df.writeExcel(file, sheetName = "allPersons") + df.writeExcel(file, sheetName = "allPersons") // Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons - val happyPersonsSheet = df.filter { person -> person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "happyPersons", keepFile = true) + df.filter { person -> person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "happyPersons", keepFile = true) // Add a new sheet to the previous file without replacing it, by setting keepFile = true -> Current sheets: allPersons, happyPersons, unhappyPersons - val unhappyPersonsSheet = df.filter { person -> !person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "unhappyPersons", keepFile = true) + df.filter { person -> !person.isHappy }.remove("isHappy").writeExcel(file, sheetName = "unhappyPersons", keepFile = true) // SampleEnd } } From b45557a785493a28128f49cf789da2247bb92c24 Mon Sep 17 00:00:00 2001 From: LeandroC89 Date: Sun, 23 Oct 2022 19:06:23 +0100 Subject: [PATCH 6/6] - Changed writeExcel location to temporary file Signed-off-by: LeandroC89 --- .gitignore | 1 - .../kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index e78af1c176..43306037d2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ .gradle build .ipynb_checkpoints -/dataframe-excel/src/test/resources/generated_wb.xlsx diff --git a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt index c34da89138..10b064fab3 100644 --- a/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt +++ b/dataframe-excel/src/test/kotlin/org/jetbrains/kotlinx/dataframe/io/XlsxTest.kt @@ -114,13 +114,13 @@ class XlsxTest { fun `write to new sheet when keepFile is true`() { val names = (1..5).map { "column$it" } val df = dataFrameOf(names).randomDouble(7) - val fileLoc = testResource("generated_wb.xlsx").toURI().toString().removeRange(0, 6) + val fileLoc = Files.createTempFile("generated_wb", ".xlsx").toFile() df.writeExcel(fileLoc, sheetName = "TestSheet1") df.writeExcel(fileLoc, sheetName = "TestSheet2", keepFile = true) - val testSheet1Df = DataFrame.readExcel(testResource("generated_wb.xlsx"), sheetName = "TestSheet1") - val testSheet2Df = DataFrame.readExcel(testResource("generated_wb.xlsx"), sheetName = "TestSheet2") + val testSheet1Df = DataFrame.readExcel(fileLoc, sheetName = "TestSheet1") + val testSheet2Df = DataFrame.readExcel(fileLoc, sheetName = "TestSheet2") testSheet1Df.columnNames() shouldBe testSheet2Df.columnNames() }