Skip to content

Commit

Permalink
New functions coordinates_to_cell_name and set_sheet_row has been add…
Browse files Browse the repository at this point in the history
…ed (#1)

- Update unit tests and docs for the function
- Sort function by alphabet order
  • Loading branch information
zhangyimingdatiancai authored Dec 1, 2024
1 parent d3703c5 commit aeb5cfc
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 65 deletions.
71 changes: 65 additions & 6 deletions excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@
import types_go
from types_py import *
from ctypes import (
CDLL,
byref,
c_bool,
c_char_p,
c_char,
c_int,
c_char_p,
POINTER,
byref,
c_ubyte,
string_at,
cast,
CDLL,
create_string_buffer,
POINTER,
pointer,
string_at,
)
import os
import platform
Expand Down Expand Up @@ -844,7 +845,7 @@ def set_sheet_background_from_bytes(
Args:
sheet (str): The worksheet name
extension (str): The cell reference
extension (str): The image extension
picture (bytes): The contents buffer of the file
Returns:
Expand All @@ -861,6 +862,64 @@ def set_sheet_background_from_bytes(
).decode(ENCODE)
return None if err == "" else Exception(err)

def set_sheet_row(
self,
sheet: str,
cell: str,
values: list[None | int | str | bool | datetime | date],
) -> Exception | None:
"""
Writes cells to row by given worksheet name, starting cell reference and
cell values list.
Args:
sheet (str): The worksheet name
cell (str): The cell reference
values (bytes): The cell values
Returns:
Exception | None: Returns None if no error occurred,
otherwise returns an Exception with the message.
"""
lib.SetSheetRow.restype = c_char_p
vals = (types_go._Interface * len(values))()
for i, value in enumerate(values):
vals[i] = py_value_to_c_interface(value)
err = lib.SetSheetRow(
self.file_index,
sheet.encode(ENCODE),
cell.encode(ENCODE),
byref(vals),
len(vals),
).decode(ENCODE)
return None if err == "" else Exception(err)


def coordinates_to_cell_name(
col: int, row: int, *abs: bool
) -> Tuple[str, Exception | None]:
"""
Converts [X, Y] coordinates to alpha-numeric cell name or returns an error.
Args:
col (int): The column number.
row (int): The row number.
*abs (bool): Optional boolean indicating whether to use absolute
references. If provided and True, the cell name will use absolute
references (e.g., $A$1).
Returns:
Tuple[str, Exception | None]: A tuple containing the cell name as a
string and an Exception if an error occurred, otherwise None.
"""
lib.CoordinatesToCellName.restype = types_go._CoordinatesToCellNameResult
options = False
if len(abs) > 0:
options = abs[0]
res = lib.CoordinatesToCellName(col, row, c_bool(options))
err = res.err.decode(ENCODE)
return res.cell.decode(ENCODE), None if err == "" else Exception(err)


def new_file() -> File:
"""
Expand Down
150 changes: 91 additions & 59 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,18 @@ func cInterfaceToGo(val C.struct_Interface) interface{} {
}
}

// CoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell name
// or returns an error.
//
//export CoordinatesToCellName
func CoordinatesToCellName(col, row int, abs bool) C.struct_CoordinatesToCellNameResult {
cell, err := excelize.CoordinatesToCellName(col, row, abs)
if err != nil {
return C.struct_CoordinatesToCellNameResult{cell: C.CString(cell), err: C.CString(err.Error())}
}
return C.struct_CoordinatesToCellNameResult{cell: C.CString(cell), err: C.CString(errNil)}
}

// Close closes and cleanup the open temporary file for the spreadsheet.
//
//export Close
Expand Down Expand Up @@ -621,6 +633,25 @@ func GetRows(idx int, sheet *C.char, opts *C.struct_Options) C.struct_GetRowsRes
return ret
}

// GetStyle provides a function to get style definition by given style index.
//
//export GetStyle
func GetStyle(idx, styleID int) C.struct_GetStyleResult {
f, ok := files.Load(idx)
if !ok {
return C.struct_GetStyleResult{err: C.CString(errFilePtr)}
}
style, err := f.(*excelize.File).GetStyle(styleID)
if err != nil {
return C.struct_GetStyleResult{err: C.CString(err.Error())}
}
cVal, err := goValueToC(reflect.ValueOf(*style), reflect.ValueOf(&C.struct_Style{}))
if err != nil {
return C.struct_GetStyleResult{err: C.CString(err.Error())}
}
return C.struct_GetStyleResult{style: cVal.Elem().Interface().(C.struct_Style), err: C.CString(errNil)}
}

// NewFile provides a function to create new file by default template.
//
//export NewFile
Expand All @@ -635,6 +666,46 @@ func NewFile() int {
return idx
}

// NewSheet provides the function to create a new sheet by given a worksheet
// name and returns the index of the sheets in the workbook after it appended.
// Note that when creating a new workbook, the default worksheet named
// `Sheet1` will be created.
//
//export NewSheet
func NewSheet(idx int, sheet *C.char) C.struct_NewSheetResult {
f, ok := files.Load(idx)
if !ok {
return C.struct_NewSheetResult{idx: C.int(-1), err: C.CString(errFilePtr)}
}
idx, err := f.(*excelize.File).NewSheet(C.GoString(sheet))
if err != nil {
return C.struct_NewSheetResult{idx: C.int(idx), err: C.CString(err.Error())}
}
return C.struct_NewSheetResult{idx: C.int(idx), err: C.CString(errNil)}
}

// NewStyle provides a function to create the style for cells by given options.
// Note that the color field uses RGB color code.
//
//export NewStyle
func NewStyle(idx int, style *C.struct_Style) C.struct_NewStyleResult {
var s excelize.Style
goVal, err := cValueToGo(reflect.ValueOf(*style), reflect.TypeOf(excelize.Style{}))
if err != nil {
return C.struct_NewStyleResult{style: C.int(0), err: C.CString(err.Error())}
}
s = goVal.Elem().Interface().(excelize.Style)
f, ok := files.Load(idx)
if !ok {
return C.struct_NewStyleResult{style: C.int(0), err: C.CString(errFilePtr)}
}
styleID, err := f.(*excelize.File).NewStyle(&s)
if err != nil {
return C.struct_NewStyleResult{style: C.int(styleID), err: C.CString(err.Error())}
}
return C.struct_NewStyleResult{style: C.int(styleID), err: C.CString(errNil)}
}

// OpenFile take the name of a spreadsheet file and returns a populated
// spreadsheet file struct for it.
//
Expand Down Expand Up @@ -715,46 +786,6 @@ func SaveAs(idx int, name *C.char, opts *C.struct_Options) *C.char {
return C.CString(errNil)
}

// NewSheet provides the function to create a new sheet by given a worksheet
// name and returns the index of the sheets in the workbook after it appended.
// Note that when creating a new workbook, the default worksheet named
// `Sheet1` will be created.
//
//export NewSheet
func NewSheet(idx int, sheet *C.char) C.struct_NewSheetResult {
f, ok := files.Load(idx)
if !ok {
return C.struct_NewSheetResult{idx: C.int(-1), err: C.CString(errFilePtr)}
}
idx, err := f.(*excelize.File).NewSheet(C.GoString(sheet))
if err != nil {
return C.struct_NewSheetResult{idx: C.int(idx), err: C.CString(err.Error())}
}
return C.struct_NewSheetResult{idx: C.int(idx), err: C.CString(errNil)}
}

// NewStyle provides a function to create the style for cells by given options.
// Note that the color field uses RGB color code.
//
//export NewStyle
func NewStyle(idx int, style *C.struct_Style) C.struct_NewStyleResult {
var s excelize.Style
goVal, err := cValueToGo(reflect.ValueOf(*style), reflect.TypeOf(excelize.Style{}))
if err != nil {
return C.struct_NewStyleResult{style: C.int(0), err: C.CString(err.Error())}
}
s = goVal.Elem().Interface().(excelize.Style)
f, ok := files.Load(idx)
if !ok {
return C.struct_NewStyleResult{style: C.int(0), err: C.CString(errFilePtr)}
}
styleID, err := f.(*excelize.File).NewStyle(&s)
if err != nil {
return C.struct_NewStyleResult{style: C.int(styleID), err: C.CString(err.Error())}
}
return C.struct_NewStyleResult{style: C.int(styleID), err: C.CString(errNil)}
}

// SetActiveSheet provides a function to set the default active sheet of the
// workbook by a given index. Note that the active index is different from the
// ID returned by function GetSheetMap(). It should be greater than or equal
Expand Down Expand Up @@ -812,25 +843,6 @@ func SetCellValue(idx int, sheet, cell *C.char, value *C.struct_Interface) *C.ch
return C.CString(errNil)
}

// GetStyle provides a function to get style definition by given style index.
//
//export GetStyle
func GetStyle(idx, styleID int) C.struct_GetStyleResult {
f, ok := files.Load(idx)
if !ok {
return C.struct_GetStyleResult{err: C.CString(errFilePtr)}
}
style, err := f.(*excelize.File).GetStyle(styleID)
if err != nil {
return C.struct_GetStyleResult{err: C.CString(err.Error())}
}
cVal, err := goValueToC(reflect.ValueOf(*style), reflect.ValueOf(&C.struct_Style{}))
if err != nil {
return C.struct_GetStyleResult{err: C.CString(err.Error())}
}
return C.struct_GetStyleResult{style: cVal.Elem().Interface().(C.struct_Style), err: C.CString(errNil)}
}

// SetSheetBackgroundFromBytes provides a function to set background picture by
// given worksheet name, extension name and image data. Supported image types:
// BMP, EMF, EMZ, GIF, JPEG, JPG, PNG, SVG, TIF, TIFF, WMF, and WMZ.
Expand All @@ -848,5 +860,25 @@ func SetSheetBackgroundFromBytes(idx int, sheet, extension *C.char, picture *C.u
return C.CString(errNil)
}

// SetSheetRow writes an array to row by given worksheet name, starting
// cell reference and a pointer to array type 'slice'. This function is
// concurrency safe.
//
//export SetSheetRow
func SetSheetRow(idx int, sheet, cell *C.char, row *C.struct_Interface, length int) *C.char {
f, ok := files.Load(idx)
if !ok {
return C.CString(errFilePtr)
}
cells := make([]interface{}, length)
for i, val := range unsafe.Slice(row, length) {
cells[i] = cInterfaceToGo(val)
}
if err := f.(*excelize.File).SetSheetRow(C.GoString(sheet), C.GoString(cell), &cells); err != nil {
C.CString(err.Error())
}
return C.CString(errNil)
}

func main() {
}
15 changes: 15 additions & 0 deletions test_excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,21 @@ def test_style(self):
self.assertIsNone(f.save(excelize.Options(password="")))
self.assertIsNone(f.close())

def test_add_chart(self):
f = excelize.new_file()
for idx, row in enumerate(
[
[None, "Apple", "Orange", "Pear"],
["Small", 2, 3, 3],
["Normal", 5, 2, 4],
["Large", 6, 7, 8],
]
):
cell, err = excelize.coordinates_to_cell_name(1, idx + 1, False)
self.assertIsNone(err)
self.assertIsNone(f.set_sheet_row("Sheet1", cell, row))
self.assertIsNone(f.save_as("TestAddChart.xlsx"))

def test_type_convert(self):
class _T2(Structure):
_fields_ = [
Expand Down
5 changes: 5 additions & 0 deletions types_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ struct Style {
bool NegRed;
};

struct CoordinatesToCellNameResult {
char* cell;
char* err;
};

struct OptionsResult {
int idx;
char* err;
Expand Down
7 changes: 7 additions & 0 deletions types_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ class _Style(Structure):
]


class _CoordinatesToCellNameResult(Structure):
_fields_ = [
("cell", c_char_p),
("err", c_char_p),
]


class _GetCellValueResult(Structure):
_fields_ = [
("val", c_char_p),
Expand Down

0 comments on commit aeb5cfc

Please sign in to comment.