Skip to content

Commit

Permalink
Add 4 new functions: set_sheet_col, set_sheet_dimension, set_sheet_na…
Browse files Browse the repository at this point in the history
…me and set_sheet_props

- Update unit tests and docs for the function
  • Loading branch information
xuri committed Dec 30, 2024
1 parent 2342461 commit e8f38fe
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 1 deletion.
104 changes: 103 additions & 1 deletion excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def load_lib():
lib = CDLL(os.path.join(os.path.dirname(__file__), load_lib()))
ENCODE = "utf-8"
__version__ = "0.0.2"
uppercase_words = ["id", "sq", "xml"]
uppercase_words = ["id", "rgb", "sq", "xml"]


def py_to_base_ctype(py_value, c_type):
Expand Down Expand Up @@ -2363,6 +2363,108 @@ def set_sheet_background_from_bytes(
).decode(ENCODE)
return None if err == "" else Exception(err)

def set_sheet_col(
self,
sheet: str,
cell: str,
values: List[Union[None, int, str, bool, datetime, date]],
) -> Optional[Exception]:
"""
Writes cells to column by given worksheet name, starting cell reference
and cell values list.
Args:
sheet (str): The worksheet name
cell (str): The cell reference
values (List[Union[None, int, str, bool, datetime, date]]): The cell
values
Returns:
Optional[Exception]: Returns None if no error occurred,
otherwise returns an Exception with the message.
"""
lib.SetSheetCol.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.SetSheetCol(
self.file_index,
sheet.encode(ENCODE),
cell.encode(ENCODE),
byref(vals),
len(vals),
).decode(ENCODE)
return None if err == "" else Exception(err)

def set_sheet_dimension(self, sheet: str, range_ref: str) -> Optional[Exception]:
"""
Set or remove the used range of the worksheet by a given range
reference. It specifies the row and column bounds of used cells in the
worksheet. The range reference is set using the A1 reference style
(e.g., "A1:D5"). Passing an empty range reference will remove the used
range of the worksheet.
Args:
sheet (str): The worksheet name
range_ref (str): The top-left and right-bottom cell range reference
Returns:
Optional[Exception]: Returns None if no error occurred,
otherwise returns an Exception with the message.
"""
lib.SetSheetDimension.restype = c_char_p
err = lib.SetSheetDimension(
self.file_index,
sheet.encode(ENCODE),
range_ref.encode(ENCODE),
).decode(ENCODE)
return None if err == "" else Exception(err)

def set_sheet_name(self, source: str, target: str) -> Optional[Exception]:
"""
Set the worksheet name by given source and target worksheet names.
Maximum 31 characters are allowed in sheet title and this function only
changes the name of the sheet and will not update the sheet name in the
formula or reference associated with the cell. So there may be problem
formula error or reference missing.
Args:
source (str): The source sheet name
target (str): The target sheet name
Returns:
Optional[Exception]: Returns None if no error occurred,
otherwise returns an Exception with the message.
"""
lib.SetSheetName.restype = c_char_p
err = lib.SetSheetName(
self.file_index,
source.encode(ENCODE),
target.encode(ENCODE),
).decode(ENCODE)
return None if err == "" else Exception(err)

def set_sheet_props(
self, sheet: str, opts: SheetPropsOptions
) -> Optional[Exception]:
"""
Set worksheet properties.
Args:
sheet (str): The worksheet name
opts (SheetPropsOptions): The sheet properties options
Returns:
Optional[Exception]: Returns None if no error occurred,
otherwise returns an Exception with the message.
"""
lib.SetSheetProps.restype = c_char_p
options = py_value_to_c(opts, types_go._SheetPropsOptions())
err = lib.SetSheetProps(
self.file_index, sheet.encode(ENCODE), byref(options)
).decode(ENCODE)
return None if err == "" else Exception(err)

def set_sheet_row(
self,
sheet: str,
Expand Down
74 changes: 74 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,80 @@ func SetSheetBackgroundFromBytes(idx int, sheet, extension *C.char, picture *C.u
return C.CString(errNil)
}

// SetSheetCol writes an array to column by given worksheet name, starting
// cell reference and a pointer to array type 'slice'.
//
//export SetSheetCol
func SetSheetCol(idx int, sheet, cell *C.char, slice *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(slice, length) {
cells[i] = cInterfaceToGo(val)
}
if err := f.(*excelize.File).SetSheetCol(C.GoString(sheet), C.GoString(cell), &cells); err != nil {
C.CString(err.Error())
}
return C.CString(errNil)
}

// SetSheetDimension provides the method to set or remove the used range of the
// worksheet by a given range reference. It specifies the row and column bounds
// of used cells in the worksheet. The range reference is set using the A1
// reference style(e.g., "A1:D5"). Passing an empty range reference will remove
// the used range of the worksheet.
//
//export SetSheetDimension
func SetSheetDimension(idx int, sheet, rangeRef *C.char) *C.char {
f, ok := files.Load(idx)
if !ok {
return C.CString(errFilePtr)
}
if err := f.(*excelize.File).SetSheetDimension(C.GoString(sheet), C.GoString(rangeRef)); err != nil {
C.CString(err.Error())
}
return C.CString(errNil)
}

// SetSheetName provides a function to set the worksheet name by given source and
// target worksheet names. Maximum 31 characters are allowed in sheet title and
// this function only changes the name of the sheet and will not update the
// sheet name in the formula or reference associated with the cell. So there
// may be problem formula error or reference missing.
//
//export SetSheetName
func SetSheetName(idx int, source, target *C.char) *C.char {
f, ok := files.Load(idx)
if !ok {
return C.CString(errFilePtr)
}
if err := f.(*excelize.File).SetSheetName(C.GoString(source), C.GoString(target)); err != nil {
C.CString(err.Error())
}
return C.CString(errNil)
}

// SetSheetProps provides a function to set worksheet properties.
//
//export SetSheetProps
func SetSheetProps(idx int, sheet *C.char, opts *C.struct_SheetPropsOptions) *C.char {
f, ok := files.Load(idx)
if !ok {
return C.CString(errFilePtr)
}
goVal, err := cValueToGo(reflect.ValueOf(*opts), reflect.TypeOf(excelize.SheetPropsOptions{}))
if err != nil {
return C.CString(err.Error())
}
options := goVal.Elem().Interface().(excelize.SheetPropsOptions)
if err := f.(*excelize.File).SetSheetProps(C.GoString(sheet), &options); err != nil {
C.CString(err.Error())
}
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.
Expand Down
24 changes: 24 additions & 0 deletions test_excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ def test_add_form_control(self):
),
)
)
self.assertIsNone(
f.set_sheet_props("Sheet1", excelize.SheetPropsOptions(code_name="Sheet1"))
)
with open(os.path.join("test", "vbaProject.bin"), "rb") as file:
self.assertIsNone(f.add_vba_project(file.read()))
self.assertIsNone(f.save_as(os.path.join("test", "TestAddFormControl.xlsm")))
Expand Down Expand Up @@ -1021,6 +1024,27 @@ def test_defined_name(self):
self.assertIsNone(f.save_as(os.path.join("test", "TestSetDefinedName.xlsx")))
self.assertIsNone(f.close())

def test_set_sheet_col(self):
f = excelize.new_file()
self.assertIsNone(
f.set_sheet_col(
"Sheet1",
"B1",
[
None,
"Hello",
100,
123.45,
True,
datetime.datetime(2016, 8, 30, 11, 51, 0),
],
)
)
self.assertIsNone(f.set_sheet_dimension("Sheet1", "A1:B6"))
self.assertIsNone(f.set_sheet_name("Sheet1", "SheetN"))
self.assertIsNone(f.save_as(os.path.join("test", "TestSetSheetCol.xlsx")))
self.assertIsNone(f.close())

def test_sheet_view(self):
f = excelize.new_file()
expected = excelize.ViewOptions(
Expand Down
23 changes: 23 additions & 0 deletions types_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,29 @@ struct Shape
struct RichTextRun *Paragraph;
};

// SheetPropsOptions directly maps the settings of sheet view.
struct SheetPropsOptions
{
char **CodeName;
bool *EnableFormatConditionsCalculation;
bool *Published;
bool *AutoPageBreaks;
bool *FitToPage;
int *TabColorIndexed;
char **TabColorRGB;
int *TabColorTheme;
double *TabColorTint;
bool *OutlineSummaryBelow;
bool *OutlineSummaryRight;
unsigned int *BaseColWidth;
double *DefaultColWidth;
double *DefaultRowHeight;
bool *CustomHeight;
bool *ZeroHeight;
bool *ThickTop;
bool *ThickBottom;
};

// SheetProtectionOptions directly maps the settings of worksheet protection.
struct SheetProtectionOptions
{
Expand Down
23 changes: 23 additions & 0 deletions types_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,29 @@ class _Shape(Structure):
]


class _SheetPropsOptions(Structure):
_fields_ = [
("CodeName", POINTER(c_char_p)),
("EnableFormatConditionsCalculation", POINTER(c_bool)),
("Published", POINTER(c_bool)),
("AutoPageBreaks", POINTER(c_bool)),
("FitToPage", POINTER(c_bool)),
("TabColorIndexed", POINTER(c_int)),
("TabColorRGB", POINTER(c_char_p)),
("TabColorTheme", POINTER(c_int)),
("TabColorTint", POINTER(c_double)),
("OutlineSummaryBelow", POINTER(c_bool)),
("OutlineSummaryRight", POINTER(c_bool)),
("BaseColWidth", POINTER(c_uint)),
("DefaultColWidth", POINTER(c_double)),
("DefaultRowHeight", POINTER(c_double)),
("CustomHeight", POINTER(c_bool)),
("ZeroHeight", POINTER(c_bool)),
("ThickTop", POINTER(c_bool)),
("ThickBottom", POINTER(c_bool)),
]


class _SheetProtectionOptions(Structure):
_fields_ = [
("AlgorithmName", c_char_p),
Expand Down
22 changes: 22 additions & 0 deletions types_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,28 @@ class Shape:
paragraph: Optional[List[RichTextRun]] = None


@dataclass
class SheetPropsOptions:
code_name: Optional[str] = None
enable_format_conditions_calculation: Optional[bool] = None
published: Optional[bool] = None
auto_page_breaks: Optional[bool] = None
fit_to_page: Optional[bool] = None
tab_color_indexed: Optional[int] = None
tab_color_rgb: Optional[str] = None
tab_color_theme: Optional[int] = None
tab_color_tint: Optional[float] = None
outline_summary_below: Optional[bool] = None
outline_summary_right: Optional[bool] = None
base_col_width: Optional[int] = None
default_col_width: Optional[float] = None
default_row_height: Optional[float] = None
custom_height: Optional[bool] = None
zero_height: Optional[bool] = None
thick_top: Optional[bool] = None
thick_bottom: Optional[bool] = None


@dataclass
class SheetProtectionOptions:
algorithm_name: str = ""
Expand Down

0 comments on commit e8f38fe

Please sign in to comment.