Skip to content

Commit

Permalink
fix python xlsx io for default formats
Browse files Browse the repository at this point in the history
  • Loading branch information
HLWeil committed Feb 23, 2024
1 parent 80dd1b6 commit a55336e
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 61 deletions.
55 changes: 12 additions & 43 deletions src/FsSpreadsheet.PythonIO/Cell.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ module PyCell =
/// Here it will actually show the correct DateTime. But when writing, exceljs will apply local offset.
//let dt = fsCell.ValueAsDateTime() |> System.DateTimeOffset
///// Therefore we add offset and it should work.
//let dt = dt + dt.Offset |> box |> Some
//let dt = dt.ToUniversalTime() + dt.Offset |> box |> Some
//dt
fsCell.ValueAsDateTime() |> box |> Some
fsCell.ValueAsDateTime().ToUniversalTime() |> box |> Some
| String ->
fsCell.Value |> Some
| anyElse ->
Expand All @@ -36,48 +36,17 @@ module PyCell =
/// <param name="columnIndex"></param>
/// <param name="jsCell"></param>
let toFsCell worksheetName rowIndex columnIndex (pyCell: Cell) =
let t = CellType.fromCellType pyCell.cellType |> PyCellType.toDataType
//printfn "toFsCell worksheetName: %s, rowIndex: %i, columnIndex: %i, %A" worksheetName rowIndex columnIndex (pyCell.value, pyCell.cellType)
let fsadress = FsAddress(rowIndex,columnIndex)
let createFscell = fun dt v -> FsCell(v,dt,address = fsadress)
let vTemp = string pyCell.value
let dt,v =
let dt,v = DataType.InferCellValue pyCell.value
if v = "=TRUE()" || v = "=True()" then
Boolean,box true
elif v = "=FALSE()" || v = "=False()" then
Boolean,box false
else
dt,v
FsCell(v,dt,address = fsadress)

let fscell =
match t with
| DataType.Boolean ->
let b = System.Boolean.Parse vTemp
createFscell DataType.Boolean b
| DataType.Number -> float vTemp |> createFscell DataType.Number
| DataType.Date ->
let dt = System.DateTime.Parse(vTemp)//.ToUniversalTime()
/// Without this step universal time get changed to local time? Exceljs tests will hit this.
///
/// Expected item (from test object): C2 : Sat Oct 14 2023 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit) | Date
///
/// Actual item (created here): C2 : Sat Oct 14 2023 02:00:00 GMT+0200 (Mitteleuropäische Sommerzeit) | Date
///
/// But logging hour minute showed that the values were given correctly and needed to be reinitialized.
//let dt = System.DateTime(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Minute, dt.Second)
dt |> createFscell DataType.Date
| DataType.String -> vTemp |> createFscell DataType.String
//| ValueType.Formula ->
// match jsCell.formula with
// | "TRUE()" ->
// let b = true
// createFscell DataType.Boolean b
// | "FALSE()" ->
// let b = false
// createFscell DataType.Boolean b
// | anyElse ->
// let msg = sprintf "ValueType 'Format' (%s) is not fully implemented in FsSpreadsheet and is handled as string input. In %s: (%i,%i)" anyElse worksheetName rowIndex columnIndex
// log msg
// anyElse |> createFscell DataType.String
//| ValueType.Hyperlink ->
// //log (c.value.Value?text)
// jsCell.value.Value?hyperlink |> createFscell DataType.String
| anyElse ->
let msg = sprintf "ValueType `%A` (%s) is not fully implemented in FsSpreadsheet and is handled as string input. In %s: (%i,%i)" anyElse vTemp worksheetName rowIndex columnIndex
printfn "%s" msg
createFscell DataType.String vTemp
fscell


2 changes: 1 addition & 1 deletion src/FsSpreadsheet.PythonIO/FsSpreadsheet.ExcelPy.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Fable.Openpyxl" Version="0.1.0" />
<PackageReference Include="Fable.Openpyxl" Version="0.2.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/FsSpreadsheet.PythonIO/Table.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ module PyTable =

let toFsTable(table:Table) =
let name = if isNull table.displayName then table.name else table.displayName
let ref = table?ref
let ref = table.ref
FsTable(name,FsRangeAddress(ref))
7 changes: 6 additions & 1 deletion src/FsSpreadsheet.PythonIO/Workbook.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,21 @@ module PyWorkbook =
open Fable.Core.PyInterop

let fromFsWorkbook (fsWB: FsWorkbook) : Workbook =
if fsWB.GetWorksheets().Count = 0 then
failwith "Workbook must contain at least one worksheet"
let pyWB = Workbook.create()
pyWB.remove(pyWB.active)
fsWB.GetWorksheets()
|> Seq.iter (fun ws ->
PyWorksheet.fromFsWorksheet pyWB ws |> ignore
)
//if fsWB.TryGetWorksheetByName("Sheet").IsNone then
// pyWB
pyWB

let toFsWorkbook(pyWB:Workbook) : FsWorkbook =
let fsWB = new FsWorkbook()
pyWB?worksheets |> Array.iter (fun (ws : Worksheet) ->
pyWB.worksheets |> Array.iter (fun (ws : Worksheet) ->
if ws.title <> "Sheet" && ws.values.Length <> 0 then
let w = PyWorksheet.toFsWorksheet ws
fsWB.AddWorksheet(w) |> ignore
Expand Down
16 changes: 5 additions & 11 deletions src/FsSpreadsheet.PythonIO/Worksheet.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,8 @@ module PyWorksheet =
open Fable.Openpyxl
open Fable.Core.PyInterop

type WorksheetStatic =
[<Emit("new $0(parent=$1, title=$2)")>]
abstract member create: parent:Workbook * title:string -> Worksheet

[<Import("Worksheet", "openpyxl.worksheet.worksheet")>]
let Worksheet : WorksheetStatic = nativeOnly

let fromFsWorksheet (parent : Workbook) (fsWS: FsWorksheet) : Worksheet =
let pyWS = Worksheet.create(parent,fsWS.Name)
let fromFsWorksheet (parent : Workbook) (fsWS: FsWorksheet) : Worksheet =
let pyWS = parent.create_sheet(fsWS.Name)
fsWS.Tables
|> Seq.iter (fun table ->
let pyTable = PyTable.fromFsTable table
Expand All @@ -37,8 +30,9 @@ module PyWorksheet =
)
pyWS.rows |> Array.iteri (fun rowIndex row ->
row |> Array.iteri (fun colIndex cell ->
let c = PyCell.toFsCell pyWS.title rowIndex colIndex cell
fsWS.AddCell(c) |> ignore
if cell.cellType <> "NoneType" then
let c = PyCell.toFsCell pyWS.title (rowIndex + 1) (colIndex + 1) cell
fsWS.AddCell(c) |> ignore
)
)
fsWS
5 changes: 2 additions & 3 deletions tests/FsSpreadsheet.ExcelPy.Tests/Workbook.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,9 @@ let private tests_toFsWorkbook = testList "toFsWorkbook" [

let tests_toPyWorkbook = testList "toPyWorkbook" [
testCase "empty" <| fun _ ->

let fsWB = new FsWorkbook()
let pyWB = PyWorkbook.fromFsWorkbook fsWB
let jswslist = pyWB?worksheets |> Array.length
Expect.equal jswslist 0 "both no worksheet"
Expect.fails (fun () -> PyWorkbook.fromFsWorkbook fsWB |> ignore) "no worksheet given"
testCase "worksheet" <| fun _ ->
let fsWB = new FsWorkbook()
let _ = fsWB.InitWorksheet("my awesome worksheet")
Expand Down
2 changes: 1 addition & 1 deletion tests/FsSpreadsheet.ExcelPy.Tests/Worksheet.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ let fromFsWorksheet = testList "fromFsWorksheet" [
let toFsWorksheet = testList "toFsWorksheet" [
testCase "Empty" <| fun _ ->
let wb = Workbook.create()
let pyWS = PyWorksheet.Worksheet.create(wb,wsName)
let pyWS = wb.create_sheet(wsName)
let fsWS = PyWorksheet.toFsWorksheet pyWS
Expect.equal fsWS.Name wsName "Name did not match"
Expect.equal (fsWS.CellCollection.GetCells() |> Seq.length) 0 "Cells did not match"
Expand Down
7 changes: 7 additions & 0 deletions tests/TestUtils/TestingUtils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ module Expect =

let passWithMsg (message: string) = equal true true message

let fails (f : unit -> unit) message =
try
f()
failwith $"Function should have failed but did not: {message}"
with
| _ -> ()

/// Fable compatible Expecto/Mocha unification
[<AutoOpen>]
module Test =
Expand Down

0 comments on commit a55336e

Please sign in to comment.