Package: pycel
PycelPycel is a small python library that can translate an Excel spreadsheet into
executable python code which can be run independently of Excel.The python code is based on a graph and uses caching & lazy evaluation to
ensure (relatively) fast execution.  The graph can be exported and analyzed
using tools likeGephi. See the contained example
for an illustration.Required python libraries:dateutil,networkx,numpy,openpyxl,ruamel.yaml, and optionally:matplotlib,pydotThe full motivation behind pycel including some examples & screenshots is
described in thisblog post.UsageDownload the library and run the example file.Quick start:You can use binder to see and explore the tool quickly and interactively in the
browser:The good:All the main mathematical functions (sin, cos, atan2, …) and operators
(+,/,^, …) are supported as are ranges (A5:D7), and functions like
MIN, MAX, INDEX, LOOKUP, and LINEST.The codebase is small, relatively fast and should be easy to understand
and extend.I have tested it extensively on spreadsheets with 10 sheets & more than
10000 formulae.  In that case calculation of the equations takes about 50ms
and agrees with Excel up to 5 decimal places.The bad:My development is driven by the particular spreadsheets I need to handle so
I have only added support for functions that I need.  However, it is should be
straightforward to add support for others.The code does currently support cell references so a function like OFFSET works,
but suffers from the fact that if a cell is not already compiled in, then the
function can fail.  Also, for obvious reasons, any VBA code is not compiled
but needs to be re-implemented manually on the python side.The Ugly:The resulting graph-based code is fast enough for my purposes but to make it
truly fast you would probably replace the graph with a dependency tracker
based on sparse matrices or something similar.Excel AddinIt’s possible to run pycel as an excel addin usingPyXLL. Simply place pyxll.xll and pyxll.py in the
lib directory and add the xll file to the Excel Addins list as explained in
the pyxll documentation.AcknowledgementsThis code was originally made possible thanks to the python port of
Eric Bachtal’sExcel formula parsing codeby Robin Macharg.The code currently uses a tokenizer of similar origin from theopenpyxl library.Change Log[1.0b30] - 2021-10-13ChangedBetter handle indirect cells in compiled workbooksBetter handle numpy floats in compiled workbooks[1.0b29] - 2021-09-13AddedAdd support for openpyxl >= 3.0.8[1.0b28] - 2021-08-31AddedAdd support for networkx 2.6ChangedSome minor improvements for Iterative Calculations[1.0b27] - 2021-07-10AddedAdded CHOOSE() functionAdded FORECAST() functionAdded INTERCEPT() functionAdded IFNA() functionAdded ISBLANK() functionAdded ISLOGICAL() functionAdded ISNONTEXT() functionAdded N() functionAdded NA() functionAdded SLOPE() functionAdded SUBSTITUTE() functionAdded TEXT() function  (Thanks, Luckykarter)Added TREND() functionAdded Reference Form for INDEX()Added str_params to excel_helper()Added ExcelCompiler.validate_serialized()ChangedImprove LINEST() compatibilty w/ ExcelImprove TEXT() compatibilty w/ ExcelImprove error and number handling in some Text functionsImprove IFS() to support array contextMissing references from INDIRECT() and OFFSET() resolve more oftenFixedFix #111, Incorrect implementation of YEARFRACFixed some exceptions in LINEST()Fix serialize ranges with formulasFixed a minor bug in DATE()Fixed TIMEVALUE() parsing for elapsed times[1.0b26] - 2021-06-18AddedPython 3.9 now supportedAdd bitwise functions: bitand, bitor, bitxor, bitlshift and bitrshift (Thanks, bogdan-oprescu-nxp)Add PV function (Thanks, estandiaa-marain)ChangedAllow plugins to be passed to the deserialization function from_file() (Thanks, nanaposo)RemovedDrop support for Python 3.5FixedFix openpyxl >= 3.0.4 (Thanks, ckp95)Fix HLOOKUP row_index_num validation to use num rows (Thanks, nanaposo)Fix #86, tokenize.TokenError: (‘EOF in multi-line statement’,Fix #88, Handle calcPR in workbook (Thanks, andreif)Fix #89, NPV function fails when passed range of cashflows (Thanks, jpp-0)Fix #93, AssertionError during set_value(), by adding a better error messageFix #99, Pycel raises NotImplementedError on rectangular ranges (Thanks, rmorel)Fix #103, build_operator_operand_fixup() throws #VALUE error when concatenating AddressCell objects (Thanks, nboukraa)Fix #104, Insufficient coverage and testing after recent mergesFix #105, Incorrect RPN for expressions with consecutive negations (Thanks, victorjmarin)Fix #109, String concatenation fails for particular cases (Thanks, bogdan-oprescu-nxp)Fix issue in =IF() when comparing to numpy resultFix MID() and REPLACE() and LEN() in a CSE contextFix INDEX() error handlingFix error handling for lookup variants[1.0b22] - 2019-10-17FixedFix #80, incompatible w/ networkx 2.4[1.0b21] - 2019-10-13ChangedSpeed up compileImplement defined names in multicolon rangesTokenize ‘:’ when adjoining functions as infix operatorVarious changes in prep to improve references, includingAdd reference expansion to function helpersAdd sheet to indirect() and ref_param=0 to offset()Implement is_address() helperImplement intersection and union for AddressCellFixedFix #77, empty arg in IFERROR()Fix #78, None compare and cleanup error handling for various IFS() funcs[1.0b20] - 2019-09-22ChangedImplement multi colon rangesAdd support for missing (empty) function parametersFixedFix threading issue in iterative evaluatorFix range intersection with null result for ROW and COLUMNFix #74 - Count not working for ranges[1.0b19] - 2019-09-12ChangedImplement INDIRECT & OFFSETImplement SMALL, LARGE & ROUNDDOWN  (Thanks, nanaposo)Add error message for unhandled missing function parameterFixedFix threading issue w/ CSE evaluator[1.0b18] - 2019-09-07ChangedImplement CEILING_MATH, CEILING_PRECISION, FLOOR_MATH & FLOOR_PRECISIONImplement FACT & FACTDOUBLEImplement AVERAGEIF, MAXIFS, MINIFSImplement ODD, EVEN, ISODD, ISEVEN, SIGNFixedFix #67 - Evaluation with unbounded rangeFix bugs w/ single cells for xIFS functions[1.0b17] - 2019-09-02ChangedAdd Formula Support for Multi Area Ranges from defined namesAllow ExcelCompiler init from openpyxl workbookImplement LOWER(), REPLACE(), TRIM() & UPPER()Implement DATEVALUE(), IFS() and ISERR()  (Thanks, int128t)Reorganized time and time utils and text functionsAdd excelutil.AddressMultiAreaRange.Add abs_coordinate() property to AddressRange and AddressCellCleanup import statementsFixedResolved tox version issue on travisFix defined names with Multi Area Range[1.0b16] - 2019-07-07ChangedAdd twelve date and time functionsSerialize workbook filename and use it instead of the serialization filename (Thanks, nanaposo)[1.0b15] - 2019-06-30ChangedImplement AVERAGEIFS()Take Iterative Calc Parameter defaults from workbookFixed#60, Binder Notebook Example not Working[1.0b14] - 2019-06-16ChangedAdded method to evaluate the conditional format (formulas) for a cell or cellsAdded ExcelCompiler(…, cycles=True) to allow Excel iterative calculations[1.0b13] - 2019-05-10ChangedImplement VALUE()Improve compile performance reversion from CSE workFixed#54, In normalize_year(), month % 12 can be 0 -> IllegalMonthError[1.0b12] - 2019-04-22ChangedAdd library plugin supportImprove evaluate of unbounded row/col (ie: A:B)Fix some regressions from 1.0b11[1.0b11] - 2019-04-21AddedImplement LEFT()Implement ISERROR()Implement FIND()Implement ISNUMBER()Implement SUMPRODUCT()Implement CEILING()Implement TRUNC() and FLOOR()Add support for LOG()Improve ABS(), INT() and ROUND()Add quoted_address() method to AddressRange and AddressCellAdd public interface to get list of formula_cells()Add NotImplementedError for “linked” sheet namesAdd reference URL to function infoAdded considerable extensions to CSE Array Formula SupportAdd CSE Array handling to excelformula and excelcompilerChange Row, Column & Index to rectangular arrays onlyAdd in_array_formula_contextAdd cse_array_wrapper() to allow calling functions in array contextAdd error_string_wrapper() to check for excel errorsMove math_wrap() to function_helpers.Handle Direct CSE Array in cellReorganize CSE Array Formula handling in excelwrapperFor CSE Arrays that are smaller than target fill w/ NoneTrim oversize array results to fit target rangeImprove needed addresses parser from python codeImprove _coerce_to_number() and _numerics() for CSE arraysRemove formulas from excelwrapper._OpxRange()ChangedRefactored ExcelWrapper, ExcelFormula & ExcelCompiler to allow…Refactored function_helpers to add decorators for excelizing library functionsImproved various messages and exceptions in validate_calcs() and trim_graph()Improve Some NotImplementedError() messagesOnly build compiler eval context onceFixedAddress Range Union and Intersection need sheet_nameFix function info for paired functions from same lineFix Range IntersectionFix Unary Minus on Empty cellFix ISNA()Fix AddressCell create from tuplePower(0,-1) now returns DIV0Cleanup index()[1.0b8] - 2019-03-20AddedImplement operators for Array FormulasImplement concatenate and concatImplement subtotalAdd support for expanding array formulasAdd support for table relative referencesAdd function information methodsChangedImprove messages for validate_calcs and not implemented functionsFixedFix column and row for array formulas[1.0b7] - 2019-03-10AddedImplement Array (CSE) FormulasFixedFix #45 - Unbounded Range Addresses (ie: A:B or 1:2) broken[1.0b6] - 2019-03-03FixedFix #42 - ‘ReadOnlyWorksheet’ object has no attribute ‘iter_cols’Fix #43 - Fix error with leading/trailing whitespace[1.0b5] - 2019-02-24AddedImplement XOR(), NOT(), TRUE(), FALSE()Improve error handling for AND(), OR()Implement POWER() function[1.0b4] - 2019-02-17ChangedMove to openpyxl 2.6+RemovedRemove support for Python 3.4[1.0b3] - 2019-02-02ChangedWork around openpyxl returning datetimesPin to openpyxl 2.5.12 to avoid bug in 2.5.14 (fixed in PR #315)[1.0b2] - 2019-01-05ChangedMuch work to better match Excel error processingExtend validate_calcs() to allow testing entire workbookImprovements to match(), including wildcard supportFinished implementing match(), lookup(), vlookup() and hlookup()Implement COLUMN() and ROW()Implement % operatorImplement len()Implement binary base number Excel functions (hex2dec, etc.)FixedFix PI()[1.0b0] - 2018-12-25AddedConverted to Python 3.4+Removed Windows Excel COM driver (openpyxl is used for all xlsx reading)Add support for defined namesAdd support for structured referencesFix support for relative formulasset_value() and evaluate() support ranges and listsAdd several more library functionsAdd AddressRange and AddressCell classes to encapsulate address calcsAdd validate_calcs() to aid debugging excellib functionsAddbuildfeature which can limit recompile to only when excel file changesChangedImproved handling for #DIV0! and #VALUE!Tests run on Python 3.4, 3.5, 3.6, 3.7 (via tox)Heavily refactored ExcelCompilerMoved all formula evaluation, parsing, etc, code to ExcelFormula classConvert to using openpyxl tokenizerConverted prints to logging callsConvert to using pytestAdd support for travis and codecov.io100% unit test coverage (mostly)Add debuggable formula evaluationCleanup generated Python code to make easier to readAdd a text format (yaml or json) serialization formatflake8 (pep8) checks addedpip now handles which Python versions can be usedRelease to PyPIDocs updatedRemovedPython 2 no longer supportedFixedNumerous[0.0.1] - (UNRELEASED)Original version available fromDirk Ggorissen’s Pycel Github Page.Supports Python 2