Skip to content

Commit

Permalink
Python version 3.10 or later required
Browse files Browse the repository at this point in the history
- Add 386 arch support
- Update GitHub Action config
- New functions auto_filter, calc_cell_value and set_cell_formula has been added
- Improve compatible with Python 3.9
- Update unit tests and docs of the function
- Add pull request template
  • Loading branch information
xuri committed Dec 9, 2024
1 parent 15df3dc commit a55dc75
Show file tree
Hide file tree
Showing 10 changed files with 443 additions and 29 deletions.
98 changes: 95 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ jobs:
strategy:
matrix:
go-version: [1.23.x]
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.13]
os: [ubuntu-24.04, macos-latest, windows-latest]
python-version: ["3.10", "3.11", "3.12", "3.13"]
targetplatform: [x64]

runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -56,9 +56,101 @@ jobs:
run: go build -buildmode=c-shared -o libexcelize.arm64.darwin.dylib main.go && coverage run -m unittest

- name: Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
flags: unittests
name: codecov-umbrella

build:
runs-on: macos-latest
needs: [test]
if: github.event_name == 'release' && github.event.action == 'published'

steps:

- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.23.x
cache: false

- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Checkout code
uses: actions/checkout@v4

- name: Get dependencies
run: |
env GO111MODULE=on go vet ./...
pip install coverage
- name: Build Shared Library
env:
CGO_ENABLED: 1
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew tap messense/macos-cross-toolchains
brew install FiloSottile/musl-cross/musl-cross i686-unknown-linux-gnu mingw-w64
wget https://github.com/mstorsjo/llvm-mingw/releases/download/20241203/llvm-mingw-20241203-ucrt-macos-universal.tar.xz
tar -xzf llvm-mingw-20241203-ucrt-macos-universal.tar.xz
export PATH="$(pwd)/llvm-mingw-20241203-ucrt-macos-universal/bin:$PATH"
CC=i686-linux-gnu-gcc GOOS=linux GOARCH=386 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.386.linux.so main.go
CC=x86_64-linux-musl-gcc GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.amd64.linux.so main.go
CC=aarch64-linux-musl-gcc GOOS=linux GOARCH=arm64 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.arm64.linux.so main.go
CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.amd64.windows.dll main.go
CC=i686-w64-mingw32-gcc GOOS=windows GOARCH=386 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.386.windows.dll main.go
CC=aarch64-w64-mingw32-gcc GOOS=windows GOARCH=arm64 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.arm64.windows.dll main.go
CC=gcc GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.arm64.darwin.dylib main.go
CC=gcc GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -buildmode=c-shared -o libexcelize.amd64.darwin.dylib main.go
rm -f libexcelize.*.h
- uses: actions/upload-artifact@v4
with:
name: libexcelize
path: |
libexcelize.386.linux.so
libexcelize.amd64.linux.so
libexcelize.arm64.linux.so
libexcelize.amd64.windows.dll
libexcelize.386.windows.dll
libexcelize.arm64.windows.dll
libexcelize.arm64.darwin.dylib
libexcelize.amd64.darwin.dylib
publish:
runs-on: ubuntu-latest
needs: [build]
environment:
name: pypi
url: https://pypi.org/p/excelize
permissions:
id-token: write

if: github.event_name == 'release' && github.event.action == 'published'
steps:
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Checkout code
uses: actions/checkout@v4

- name: Download Artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
path: ./

- name: Build Python Package
run: |
pip install build setuptools wheel
python -m build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
45 changes: 45 additions & 0 deletions PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# PR Details

<!--- Provide a general summary of your changes in the Title above -->

## Description

<!--- Describe your changes in detail -->

## Related Issue

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## How Has This Been Tested

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Docs change / refactoring / dependency upgrade
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<a href="https://www.paypal.com/paypalme/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a>
</p>

Package excelize-py is a Python port of Go [Excelize](https://github.com/xuri/excelize) library, providing a set of functions that allow you to write and read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and writing spreadsheet documents generated by Microsoft Excel&trade; 2007 and later. Supports complex components by high compatibility, and provided streaming API for generating or reading data from a worksheet with huge amounts of data. This library needs Python version 3.9 or later. The full API docs can be found at [docs reference](https://xuri.me/excelize/).
Package excelize-py is a Python port of Go [Excelize](https://github.com/xuri/excelize) library, providing a set of functions that allow you to write and read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and writing spreadsheet documents generated by Microsoft Excel&trade; 2007 and later. Supports complex components by high compatibility, and provided streaming API for generating or reading data from a worksheet with huge amounts of data. This library needs Python version 3.10 or later. The full API docs can be found at [docs reference](https://xuri.me/excelize/).

## Platform Compatibility

Expand Down
134 changes: 127 additions & 7 deletions excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
files. Supports reading and writing spreadsheet documents generated by Microsoft
Excel™ 2007 and later. Supports complex components by high compatibility, and
provided streaming API for generating or reading data from a worksheet with huge
amounts of data. This library needs Python version 3.9 or later.
amounts of data. This library needs Python version 3.10 or later.
"""

from dataclasses import fields
Expand Down Expand Up @@ -45,6 +45,10 @@ def load_lib():
"amd64": "amd64",
"aarch64": "arm64",
},
"32bit": {
"i386": "386",
"i686": "386",
},
},
"darwin": {
"64bit": {
Expand All @@ -59,6 +63,10 @@ def load_lib():
"amd64": "amd64",
"arm64": "arm64",
},
"32bit": {
"i386": "386",
"i686": "386",
},
},
}
if system in ext_map and arch in arch_map.get(system, {}):
Expand Down Expand Up @@ -434,11 +442,13 @@ def save(self, *opts: Options) -> Exception | None:
otherwise returns an Exception with the message.
"""
err, lib.Save.restype = None, c_char_p
if len(opts) > 0:
options = py_value_to_c(opts[0], types_go._Options())
err = lib.Save(self.file_index, byref(options)).decode(ENCODE)
return None if err == "" else err
err = lib.Save(self.file_index, POINTER(types_go._Options)()).decode(ENCODE)
options = POINTER(types_go._Options)()
options = (
byref(py_value_to_c(opts[0], types_go._Options()))
if opts
else POINTER(types_go._Options)()
)
err = lib.Save(self.file_index, options).decode(ENCODE)
return None if err == "" else Exception(err)

def save_as(self, filename: str, *opts: Options) -> Exception | None:
Expand Down Expand Up @@ -866,6 +876,78 @@ def add_table(self, sheet: str, table: Table) -> Exception | None:
).decode(ENCODE)
return None if err == "" else Exception(err)

def auto_filter(
self,
sheet: str,
range_ref: str,
opts: list[AutoFilterOptions],
) -> Exception | None:
"""
Add auto filter in a worksheet by given worksheet name, range reference
and settings. An auto filter in Excel is a way of filtering a 2D range
of data based on some simple criteria.
Column defines the filter columns in an auto filter range based on simple
criteria
It isn't sufficient to just specify the filter condition. You must also
hide any rows that don't match the filter condition. Rows are hidden using
the SetRowVisible function. Excelize can't filter rows automatically since
this isn't part of the file format.
Args:
sheet (str): The worksheet name
range_ref (str): The top-left and right-bottom cell range reference
opts (list[AutoFilterOptions]): The auto filter options
Returns:
Exception | None: Returns None if no error occurred,
otherwise returns an Exception with the message.
"""
lib.AutoFilter.restype = c_char_p
options = (types_go._AutoFilterOptions * len(opts))()
for i, opt in enumerate(opts):
options[i] = py_value_to_c(opt, types_go._AutoFilterOptions())
err = lib.AutoFilter(
self.file_index,
sheet.encode(ENCODE),
range_ref.encode(ENCODE),
byref(options),
len(options),
).decode(ENCODE)
return None if err == "" else Exception(err)

def calc_cell_value(
self, sheet: str, cell: str, *opts: Options
) -> Tuple[str, Exception | None]:
"""
Get calculated cell value. This feature is currently in working
processing. Iterative calculation, implicit intersection, explicit
intersection, array formula, table formula and some other formulas are
not supported currently.
Args:
sheet (str): The worksheet name
cell (str): The cell reference
*opts (Options): Optional parameters for get cell value
Returns:
Tuple[str, Exception | None]: A tuple containing the calculation
result as a string and an exception if an error occurred, otherwise
None.
"""
lib.CalcCellValue.restype = types_go._CalcCellValueResult
options = (
byref(py_value_to_c(opts[0], types_go._Options()))
if opts
else POINTER(types_go._Options)()
)
res = lib.CalcCellValue(
self.file_index, sheet.encode(ENCODE), cell.encode(ENCODE), options
)
err = res.err.decode(ENCODE)
return res.val.decode(ENCODE), None if err == "" else Exception(err)

def close(self) -> Exception | None:
"""
Closes and cleanup the open temporary file for the spreadsheet.
Expand Down Expand Up @@ -1203,6 +1285,43 @@ def set_active_sheet(self, index: int) -> Exception | None:
err = lib.SetActiveSheet(self.file_index, index).decode(ENCODE)
return None if err == "" else Exception(err)

def set_cell_formula(
self, sheet: str, cell: str, formula: str, *opts: FormulaOpts
) -> Exception | None:
"""
Set formula on the cell is taken according to the given worksheet name
and cell formula settings. The result of the formula cell can be
calculated when the worksheet is opened by the Office Excel application
or can be using the "CalcCellValue" function also can get the calculated
cell value. If the Excel application doesn't calculate the formula
automatically when the workbook has been opened, please call
"update_linked_value" after setting the cell formula functions.
Parameters:
sheet (str): The worksheet name
cell (str): The cell reference
formula (str): The cell formula
*opts (FormulaOpts): The formula options
Returns:
Exception | None: Returns None if no error occurred,
otherwise returns an Exception with the message.
"""
err, lib.SetCellFormula.restype = None, c_char_p
options = (
byref(py_value_to_c(opts[0], types_go._FormulaOpts()))
if opts
else POINTER(types_go._FormulaOpts)()
)
err = lib.SetCellFormula(
self.file_index,
sheet.encode(ENCODE),
cell.encode(ENCODE),
formula.encode(ENCODE),
options,
).decode(ENCODE)
return None if err == "" else Exception(err)

def set_cell_style(
self, sheet: str, top_left_cell: str, bottom_right_cell: str, style_id: int
) -> Exception | None:
Expand Down Expand Up @@ -1305,7 +1424,8 @@ def set_sheet_row(
Args:
sheet (str): The worksheet name
cell (str): The cell reference
values (bytes): The cell values
values (list[None | int | str | bool | datetime | date]): The cell
values
Returns:
Exception | None: Returns None if no error occurred,
Expand Down
Loading

0 comments on commit a55dc75

Please sign in to comment.