Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ finally:

With Excelize chart generation and management is as easy as a few lines of code. You can build charts based on data in your worksheet or generate charts without any data in your worksheet at all.

<p align="center"><img width="650" src="./chart.png" alt="Excelize"></p>
<p align="center"><img width="650" src="https://github.com/xuri/excelize-py/raw/main/chart.png" alt="Excelize"></p>

```python
import excelize
Expand Down
2 changes: 1 addition & 1 deletion README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ finally:

使用 Excelize 生成图表十分简单,仅需几行代码。您可以根据工作表中的已有数据构建图表,或向工作表中添加数据并创建图表。

<p align="center"><img width="650" src="./chart.png" alt="使用 Excelize 在 Excel 电子表格文档中创建图表"></p>
<p align="center"><img width="650" src="https://github.com/xuri/excelize-py/raw/main/chart.png" alt="使用 Excelize 在 Excel 电子表格文档中创建图表"></p>

```python
import excelize
Expand Down
60 changes: 53 additions & 7 deletions excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from dataclasses import fields
from datetime import datetime, date, time
from enum import Enum
from typing import Tuple, get_args, get_origin, List, Optional, Union
from typing import Tuple, get_args, get_origin, Dict, List, Optional, Union
from ctypes import (
byref,
c_bool,
Expand Down Expand Up @@ -1692,14 +1692,30 @@ def get_col_width(self, sheet: str, col: str) -> float:
```
"""
lib.GetColWidth.restype = types_go._Float64ErrorResult
res = lib.GetColWidth(
self.file_index, sheet.encode(ENCODE), col.encode(ENCODE)
)
res = lib.GetColWidth(self.file_index, sheet.encode(ENCODE), col.encode(ENCODE))
err = res.err.decode(ENCODE)
if not err:
return res.val
raise RuntimeError(err)

def get_comments(self, sheet: str) -> List[Comment]:
"""
GetComments retrieves all comments in a worksheet by given worksheet
name.

Returns:
List[Comment]: Return the comment list if no error occurred,
otherwise raise a RuntimeError with the message.
"""
lib.GetComments.restype = types_go._GetCommentsResult
res = lib.GetComments(self.file_index, sheet.encode(ENCODE))
result = c_value_to_py(res, GetCommentsResult())
if res.Err:
err = res.Err.decode(ENCODE)
if err:
raise RuntimeError(err)
return result.comments if result and result.comments else []

def get_default_font(self) -> str:
"""
Get the default font name currently set in the workbook. The spreadsheet
Expand Down Expand Up @@ -1827,6 +1843,38 @@ def get_sheet_index(self, sheet: str) -> int:
return res.val
raise RuntimeError(err)

def get_sheet_list(self) -> List[str]:
"""
GetSheetList provides a function to get worksheets, chart sheets, and
dialog sheets name list of the workbook.

Returns:
List[str]: Return the sheet name list if no error occurred,
otherwise return an empty list.
"""
lib.GetSheetList.restype = types_go._StringArrayErrorResult
res = lib.GetSheetList(self.file_index)
arr = c_value_to_py(res, StringArrayErrorResult()).arr
return arr if arr else []

def get_sheet_map(self) -> Dict[int, str]:
"""
GetSheetMap provides a function to get worksheets, chart sheets, dialog
sheets ID, and name maps of the workbook.

Returns:
dict[int, str]: Return the sheet ID and name map if no error
occurred, otherwise return an empty dictionary.
"""
lib.GetSheetMap.restype = types_go._GetSheetMapResult
sheet_map = dict()
res = lib.GetSheetMap(self.file_index)
result = c_value_to_py(res, GetSheetMapResult()).arr
if result:
for item in result:
sheet_map[item.k] = item.v
return sheet_map

def get_sheet_name(self, sheet: int) -> str:
"""
Get the sheet name of the workbook by the given sheet index.
Expand Down Expand Up @@ -3744,9 +3792,7 @@ def open_file(filename: str, *opts: Options) -> File:
raise RuntimeError(err)


def open_reader(
buffer: bytes, *opts: Options
) -> Optional[File]:
def open_reader(buffer: bytes, *opts: Options) -> Optional[File]:
"""
Read data stream from bytes and return a populated spreadsheet file.

Expand Down
80 changes: 77 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,10 @@ func AddFormControl(idx int, sheet *C.char, opts *C.struct_FormControl) *C.char
return C.CString(emptyString)
}

// Add picture in a sheet by given picture format set (such as offset, scale,
// aspect ratio setting and print settings) and file path, supported image
// types: BMP, EMF, EMZ, GIF, JPEG, JPG, PNG, SVG, TIF, TIFF, WMF, and WMZ.
// AddPicture add picture in a sheet by given picture format set (such as
// offset, scale, aspect ratio setting and print settings) and file path,
// supported image types: BMP, EMF, EMZ, GIF, JPEG, JPG, PNG, SVG, TIF, TIFF,
// WMF, and WMZ.
//
//export AddPicture
func AddPicture(idx int, sheet, cell, name *C.char, opts *C.struct_GraphicOptions) *C.char {
Expand Down Expand Up @@ -1189,6 +1190,29 @@ func GetColWidth(idx int, sheet, col *C.char) C.struct_Float64ErrorResult {
return C.struct_Float64ErrorResult{val: C.double(val), err: C.CString(emptyString)}
}

// GetComments retrieves all comments in a worksheet by given worksheet name.
//
//export GetComments
func GetComments(idx int, sheet *C.char) C.struct_GetCommentsResult {
f, ok := files.Load(idx)
if !ok {
return C.struct_GetCommentsResult{Err: C.CString(errFilePtr)}
}
comments, err := f.(*excelize.File).GetComments(C.GoString(sheet))
if err != nil {
return C.struct_GetCommentsResult{Err: C.CString(err.Error())}
}
cArray := C.malloc(C.size_t(len(comments)) * C.size_t(unsafe.Sizeof(C.struct_Comment{})))
for i, r := range comments {
cVal, err := goValueToC(reflect.ValueOf(r), reflect.ValueOf(&C.struct_Comment{}))
if err != nil {
return C.struct_GetCommentsResult{Err: C.CString(err.Error())}
}
*(*C.struct_Comment)(unsafe.Pointer(uintptr(unsafe.Pointer(cArray)) + uintptr(i)*unsafe.Sizeof(C.struct_Comment{}))) = cVal.Elem().Interface().(C.struct_Comment)
}
return C.struct_GetCommentsResult{CommentsLen: C.int(len(comments)), Comments: (*C.struct_Comment)(cArray), Err: C.CString(emptyString)}
}

// GetDefaultFont provides the default font name currently set in the
// workbook. The spreadsheet generated by excelize default font is Calibri.
//
Expand Down Expand Up @@ -1302,6 +1326,56 @@ func GetSheetIndex(idx int, sheet *C.char) C.struct_IntErrorResult {
return C.struct_IntErrorResult{val: C.int(idx), err: C.CString(emptyString)}
}

// GetSheetList provides a function to get worksheets, chart sheets, and
// dialog sheets name list of the workbook.
//
//export GetSheetList
func GetSheetList(idx int) C.struct_StringArrayErrorResult {
f, ok := files.Load(idx)
if !ok {
return C.struct_StringArrayErrorResult{Err: C.CString(errFilePtr)}
}
result := f.(*excelize.File).GetSheetList()
cArray := C.malloc(C.size_t(len(result)) * C.size_t(unsafe.Sizeof(uintptr(0))))
for i, v := range result {
*(*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(cArray)) + uintptr(i)*unsafe.Sizeof(uintptr(0)))) = unsafe.Pointer(C.CString(v))
}
return C.struct_StringArrayErrorResult{ArrLen: C.int(len(result)), Arr: (**C.char)(cArray), Err: C.CString(emptyString)}
}

// GetSheetMap provides a function to get worksheets, chart sheets, dialog
// sheets ID and name map of the workbook.
//
//export GetSheetMap
func GetSheetMap(idx int) C.struct_GetSheetMapResult {
type IntStringResult struct {
K int
V string
}
type GetSheetMapResult struct {
Arr []IntStringResult
Err string
}
var result GetSheetMapResult
f, ok := files.Load(idx)
if !ok {
return C.struct_GetSheetMapResult{
Err: C.CString(errFilePtr),
}
}
for k, v := range f.(*excelize.File).GetSheetMap() {
result.Arr = append(result.Arr, IntStringResult{K: k, V: v})
}

cVal, err := goValueToC(reflect.ValueOf(result), reflect.ValueOf(&C.struct_GetSheetMapResult{}))
if err != nil {
return C.struct_GetSheetMapResult{Err: C.CString(err.Error())}
}
ret := cVal.Elem().Interface().(C.struct_GetSheetMapResult)
ret.Err = C.CString(emptyString)
return ret
}

// GetSheetName provides a function to get the sheet name by the given worksheet index.
// If the given worksheet index is invalid, it will return an error.
//
Expand Down
11 changes: 11 additions & 0 deletions test_excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ def test_style(self):
with self.assertRaises(RuntimeError) as context:
_ = f.get_sheet_index("")
self.assertEqual(str(context.exception), "the sheet name can not be blank")
self.assertEqual(f.get_sheet_list(), ["Sheet1", "Sheet2"])
self.assertEqual(len(f.get_sheet_map()), 2)
self.assertEqual(f.get_sheet_name(index), "Sheet2")

self.assertIsNone(f.set_col_outline_level("Sheet1", "D", 2))
Expand Down Expand Up @@ -735,6 +737,15 @@ def test_comment(self):
comment,
)
)
comments = f.get_comments("Sheet1")
self.assertEqual(len(comments), 1)
self.assertEqual(comments[0].cell, "A5")
self.assertEqual(comments[0].author, "Excelize")
self.assertEqual(comments[0].paragraph[0].text, comment.paragraph[0].text)
self.assertEqual(comments[0].paragraph[1].text, comment.paragraph[1].text)
with self.assertRaises(RuntimeError) as context:
f.get_comments("SheetN")
self.assertEqual(str(context.exception), "sheet SheetN does not exist")
with self.assertRaises(RuntimeError) as context:
f.add_comment("SheetN", comment)
self.assertEqual(str(context.exception), "sheet SheetN does not exist")
Expand Down
17 changes: 17 additions & 0 deletions types_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,11 @@ struct StringArrayErrorResult
char *Err;
};

struct IntStringResult {
int K;
char *V;
};

struct GetCellHyperLinkResult
{
bool link;
Expand Down Expand Up @@ -799,3 +804,15 @@ struct GetWorkbookPropsResult
struct WorkbookPropsOptions opts;
char *err;
};

struct GetSheetMapResult {
int ArrLen;
struct IntStringResult *Arr;
char *Err;
};

struct GetCommentsResult {
int CommentsLen;
struct Comment *Comments;
char *Err;
};
25 changes: 25 additions & 0 deletions types_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,12 +704,21 @@ class _BoolErrorResult(Structure):
("err", c_char_p),
]


class _Float64ErrorResult(Structure):
_fields_ = [
("val", c_double),
("err", c_char_p),
]


class _IntStringResult(Structure):
_fields_ = [
("K", c_int),
("V", c_char_p),
]


class _StringArrayErrorResult(Structure):
_fields_ = [
("ArrLen", c_int),
Expand Down Expand Up @@ -784,3 +793,19 @@ class _GetWorkbookPropsResult(Structure):
("opts", _WorkbookPropsOptions),
("err", c_char_p),
]


class _GetSheetMapResult(Structure):
_fields_ = [
("ArrLen", c_int),
("Arr", POINTER(_IntStringResult)),
("Err", c_char_p),
]


class _GetCommentsResult(Structure):
_fields_ = [
("CommentsLen", c_int),
("Comments", POINTER(_Comment)),
("Err", c_char_p),
]
18 changes: 18 additions & 0 deletions types_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,25 @@ class WorkbookProtectionOptions:
lock_windows: bool = False


@dataclass
class IntStringResult:
k: int = 0
v: str = ""


@dataclass
class StringArrayErrorResult:
arr: Optional[List[str]] = None
err: str = ""


@dataclass
class GetSheetMapResult:
arr: Optional[List[IntStringResult]] = None
err: str = ""


@dataclass
class GetCommentsResult:
comments: Optional[List[Comment]] = None
err: str = ""