### Install and Register xlOil Source: https://context7.com/cunnane/xloil/llms.txt Commands to install the xlOil package and register the add-in with Excel. ```bash # Install the package pip install xlOil # Register the add-in with Excel xloil install ``` -------------------------------- ### Configure xlOil settings Source: https://github.com/cunnane/xloil/blob/master/docs/source/Core.rst Example of defining the base path and loading plugins in the xlOil.ini configuration file. ```toml ... XLOIL_PATH='''C:\lib\xloil``` ... Plugins=["xloil_Python.dll", "xlOil_SQL.dll"] ``` -------------------------------- ### Install xlOil Addin Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/GettingStarted.rst Run this command in your terminal to register the xlOil addin with Excel. ```bash xloil install ``` -------------------------------- ### Test Python wheels Source: https://github.com/cunnane/xloil/blob/master/docs/source/Developer.rst Install and uninstall the generated wheel to verify the package structure. ```bash cd \build\staging\pypackage pip install dist/xlOil-0.3-cp37-cp37m-win_amd64.whl pip uninstall dist/xlOil-0.3-cp37-cp37m-win_amd64.whl ``` -------------------------------- ### Install xlOil Addin Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/GettingStarted.rst Run this command in your terminal to install the xlOil addin for creating Python-based Excel functions. ```bash pip install xlOil ``` -------------------------------- ### Create RTD Server with Custom Publisher Source: https://context7.com/cunnane/xloil/llms.txt Implement a custom RTD publisher in Python for fine-grained control over real-time data. This example fetches URL content periodically. ```python import xloil as xlo import asyncio _rtdServer = xlo.RtdServer() class UrlGetter(xlo.RtdPublisher): def __init__(self, url): super().__init__() self._url = url self._task = None def connect(self, num_subscribers): if self.done(): async def run(): try: while True: data = await fetch_url(self._url) _rtdServer.publish(self._url, data) await asyncio.sleep(4) except Exception as e: _rtdServer.publish(self._url, e) self._task = xlo.get_event_loop().create_task(run()) def disconnect(self, num_subscribers): if num_subscribers == 0: self.stop() return True def stop(self): if self._task is not None: self._task.cancel() def done(self): return self._task is None or self._task.done() def topic(self): return self._url @xlo.func def pyGetUrlLive(url): if _rtdServer.peek(url) is None: _rtdServer.start(UrlGetter(url)) return _rtdServer.subscribe(url) ``` -------------------------------- ### Implement fine-grained RTD control Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/Rtd.rst Uses peek, start, and subscribe to manage publishers manually. Useful for complex scenarios like URL polling. ```python _rtdServer = xlo.RtdServer() @xlo.func def pyGetUrlLive(url): if _rtdServer.peek(url) is None: publisher = UrlGetter(url) _rtdServer.start(publisher) return _rtdServer.subscribe(url) ``` -------------------------------- ### Quit xloil Application Source: https://github.com/cunnane/xloil/blob/master/tests/ManualSheets/python/TestJupyterConnection.ipynb Commented-out example for quitting the xloil application. ```python #xl.quit() ``` -------------------------------- ### Define plugin environment variables Source: https://github.com/cunnane/xloil/blob/master/docs/source/Core.rst Example of setting environment variables for the Python plugin using TOML syntax, including registry lookups and variable references. ```toml [[xlOil_Python.Environment]] xlOilPythonVersion="3.7" [[xlOil_Python.Environment]] PYTHONPATH='''''' PYTHON_LIB='''''' [[xlOil_Python.Environment]] PATH='''%PATH%;%PYTHON_LIB%;%PYTHON_LIB%\Library\bin''' ``` -------------------------------- ### Get Source File Information with xloil Source: https://github.com/cunnane/xloil/blob/master/tests/AutoSheets/TestUtils.ipynb Retrieves source file information using xloil.importer._source_file.get(). ```python xloil.importer._source_file.get(3) ``` -------------------------------- ### Call COM methods with keyword arguments Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/ExcelApplication.rst Demonstrates calling Excel COM methods using keyword arguments, noting that COM arguments must start with a capital letter. ```python xloil.app().Selection.PasteSpecial(Paste=xloil.constants.xlPasteFormulas) ``` -------------------------------- ### Automate Excel with a test runner Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/ExcelApplication.rst Example of driving Excel externally by creating an application instance, loading an XLL, and iterating through named ranges to validate test results. ```python import xloil as xlo # Create a new Excel instance and make it visible app = xlo.Application() app.visible = True # Load addin if not app.RegisterXLL("xloil.xll"): raise Exception("xloil load failed") test_results = {} for filename in ['TestUtils.xlsx, PythonTest.xlsm']: # Open the workbook in readonly mode: don't change the test source! wb = app.open(filename, read_only=True) app.calculate(full=True) # Loop through all named ranges in the workbook, looking for ones # prefixed with 'Test_'. We expect those ranges to contain True # for a successful test outcome. names = wb.to_com().Names for named_range in names: if named_range.Name.lower().startswith("Test_"): # skip one char as RefersTo always starts with '=' address = named_range.RefersTo[1:] test_results[(filename, named_range.Name)] = wb[address].value wb.close(save=False) app.quit() if not all(test_results.values()): print("-->FAILED<--") ``` -------------------------------- ### Read data from Excel ranges Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/ExcelApplication.rst Examples of reading range values using xlOil syntax versus direct COM access, noting differences in return types. ```python import xloil as xlo # if xlOil is embedded: no need to specify Application. # Returns a numpy array xlo.Range("A1:C1").value # Above is equivalent to xlo.app().range("A1:C1").value # Using COM (win32com) to access a range with empty index # Returns a tuple rather than a numpy array xlo.app().Range("A1", "C1").Value ``` -------------------------------- ### Package Python Distribution with xlOil Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/DistributingAddins.rst Use the 'xloil package' command to bundle a Python distribution, including xlOil and your custom modules, into an installer. Specify the configuration INI file and use '--hidden-import' for modules PyInstaller might miss. ```bash xloil package myaddin.ini --hidden-import excel_funcs ``` -------------------------------- ### Register a Callable Class Instance Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/Dynamic.rst Register an instance of a class that implements the __call__ method, allowing it to be used as a function in Excel. This example accumulates a total. ```python class Closure: self._total = 0 def __call__(self, x): self._total += x return x xlo.register_functions(Closure()) ``` -------------------------------- ### Create a Workbook-Specific xlOil Function Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/GettingStarted.rst Create a Python file named after your Excel workbook (e.g., MyBook.py) in the same directory. Functions defined here will be loaded when the workbook is opened. This example shows a simple addition function that can also handle arrays. ```python import xloil as xlo @xlo.func def Adder(x, y): return x + y ``` -------------------------------- ### Create and Control Excel Application Instance Source: https://context7.com/cunnane/xloil/llms.txt Shows how to create a new Excel instance, control its visibility, load add-ins, open workbooks, and perform calculations. ```python import xloil as xlo # Create new Excel instance app = xlo.Application() app.visible = True ``` ```python # Load an add-in app.RegisterXLL("xloil.xll") ``` ```python # Open workbook wb = app.open("test.xlsx", read_only=True) ``` ```python # Calculate app.calculate(full=True) ``` -------------------------------- ### Stage the xlOil build Source: https://github.com/cunnane/xloil/blob/master/docs/source/Developer.rst Run the staging script from the tools directory to prepare the build. ```bash cd \tools python stage.py ``` -------------------------------- ### Create a Ribbon in an xlOil plugin Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Cpp/CustomGUI.rst Uses XLO_PLUGIN_INIT to initialize the plugin and register the ribbon interface. ```cpp #incude void ribbonHandler(const RibbonControl& ctrl) {} std::shared_ptr theComAddin; XLO_PLUGIN_INIT(xloil::AddinContext* ctx, const xloil::PluginContext& plugin) { xloil::linkLogger(ctx, plugin); auto mapper = [=](const wchar_t* name) mutable { return ribbonHandler; }; theComAddin = makeAddinWithRibbon( L"TestXlOil", LR"( ... )", mapper); return 0; } ``` -------------------------------- ### Build Stateful Database Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_SQL/index.rst Create and populate an in-memory database using chained function calls. ```excel . A B C D 1 =xloSqlDB() MyTab Foo Bar 2 7 2 3 =xloSqlTable(A1, C1:D4, B1) 4 1 4 8 4 5 ``` -------------------------------- ### Subscribe to RTD data in C++ Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Cpp/CppRtd.rst Demonstrates creating an RTD server and subscribing to live data updates using xlOil. ```c++ #include using namespace xloil; IRtdServer& myRtdServer() { static shared_ptr ptr = newRtdServer(); static auto backgroundTask = std::async([]() { // Somehow fetch live prices here ptr->publish("SP500", ExcelObj(123)); ptr->publish("FTSE100", ExcelObj(456)); }); return *ptr; } XLO_FUNC_START( getStock(const ExcelObj& ticker) ) { auto value = myRtdServer().subscribe(tag.toString().c_str()); return returnValue(value ? *value : Const::Error(CellError::NA)); } XLO_FUNC_END(getStock); ``` -------------------------------- ### Get Linked Workbook Name with xloil Source: https://github.com/cunnane/xloil/blob/master/tests/AutoSheets/TestUtils.ipynb Retrieves the name of the currently linked workbook using xloil.linked_workbook(). ```python xloil.linked_workbook() ``` -------------------------------- ### Control Excel via COM from Jupyter Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/Jupyter.rst Use the xloil.app object to control the connected Excel instance if the xloil package is installed in the kernel. ```python app = xloil.app() app.workbooks.add() ``` -------------------------------- ### Define an xlOil function with complex type annotations Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/TypeConversion.rst Example of using multiple argument types and a return type annotation in an xlOil function. ```python @xlo.func def pySumNums(x: float, y: float, a: int = 2, b: int = 3) -> float: return x * a + y * b ``` -------------------------------- ### Python Function for Dynamic Import Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/Dynamic.rst This is an example Python function that can be dynamically imported into Excel using xloil.import_functions. Typing annotations and doc-strings are respected. ```python def greet(x:str): return f"Hello {x}!" ``` -------------------------------- ### Initialize xloil Application Source: https://github.com/cunnane/xloil/blob/master/tests/ManualSheets/python/TestJupyterConnection.ipynb Instantiate the xloil application object. ```python xl = xloil.app() ``` -------------------------------- ### Create Excel Ribbon Components with ExcelGUI Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/CustomGUI.rst Instantiate ExcelGUI to manage dynamic creation of Excel Fluent Ribbon components. The funcmap links ribbon XML callbacks to Python functions. ```python gui = xlo.ExcelGUI(r'''....''', funcmap={ 'onClick1': run_click, 'onClick2': run_click, 'onUpdate': update_text, }) ``` -------------------------------- ### Handle Dictionary and Keyword Arguments Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/TypeConversion.rst Shows how to accept a dictionary and keyword arguments as a two-column array from Excel. ```python @xlo.func def pyTestKwargs(lookup: dict, **kwargs) -> dict: lookup.update(kwargs) return lookup ``` -------------------------------- ### Register a Workbook Event Handler Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/Concepts.rst Example of registering a Python function to handle the 'WorkbookNewSheet' event. The handler receives workbook and worksheet names and writes to a cell. ```python def greet(workbook, worksheet): xlo.Range(f"[{workbook}]{worksheet}!A1") = "Hello!" xlo.event.WorkbookNewSheet += greet ``` -------------------------------- ### Create a Ribbon in a static XLL Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Cpp/CustomGUI.rst Uses XLO_DECLARE_ADDIN to register an addin and xllOpenComCall to defer ribbon creation until the COM interface is ready. ```cpp void ribbonHandler(const RibbonControl& ctrl) {} struct MyAddin { std::shared_ptr theComAddin; MyAddin() { // We need this call so that xlOil defers execution of the ribbon creation // until Excel's COM interface is ready xllOpenComCall([this]() { auto mapper = [=](const wchar_t* name) mutable { return ribbonHandler; }; theComAddin = makeAddinWithRibbon( L"TestXlOil", LR"( ... )", mapper); }); } }; XLO_DECLARE_ADDIN(MyAddin); ``` -------------------------------- ### Basic Variable Assignment in Python Source: https://github.com/cunnane/xloil/blob/master/tests/AutoSheets/TestUtils.ipynb Demonstrates a simple variable assignment in Python. ```python x=1 ``` -------------------------------- ### Reference xloil Application Constructor Source: https://github.com/cunnane/xloil/blob/master/tests/ManualSheets/python/TestJupyterConnection.ipynb Reference the `xloil.app` constructor, used for initializing the xloil application. ```python xloil.app ``` -------------------------------- ### Create xloil Address for Formulas Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/ExcelApplication.rst Use xloil.Address to create a reference for use in Excel formula strings. The address is defined by start and end row/column, and optionally a sheet name. ```python sum_start_row=0 sum_end_row=9 address = xlo.Address((sum_start_row, 1, sum_end_row, 1), sheet="Sheet1") xlo.app().Range("A1").formula = f'=SUM({address})' # Will be '=SUM(Sheet1!B1:B10)' ``` -------------------------------- ### Create a Custom Task Pane Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Cpp/CustomGUI.rst Adds a task pane to an existing COM addin instance. ```cpp std::shared_ptr taskPane(theComAddin->createTaskPane(L"xloil")); taskPane->setVisible(true); ``` -------------------------------- ### Define an xlOil Plugin Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Cpp/GettingStarted.rst Use XLO_PLUGIN_INIT to register the DLL as a plugin and XLO_FUNC_START/END macros to define Excel-callable functions. ```c++ #include XLO_PLUGIN_INIT(xloil::AddinContext* ctx, const xloil::PluginContext& plugin) { xloil::linkLogger(ctx, plugin); return 0; } using namespace xloil; XLO_FUNC_START( MyFunc(const ExcelObj* arg1, const ExcelObj* arg2) ) { auto result = arg1->toString() + ": " + arg2->toString(L"default value"); return ExcelObj::returnValue(result); } XLO_FUNC_END(MyFunc).threadsafe() .help(L"Joins two strings") .arg(L"Val1", L"First String") .arg(L"Val2", L"Second String"); ``` -------------------------------- ### Custom Return Type Converter Function Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/TypeConversion.rst A function decorated with @xlo.returner() can be used to convert Python objects to types Excel understands. This example registers a converter for `MyType` which returns the type's name. ```python @xlo.returner(typeof=MyType, register=True) def mytypename(val): return val.__name__ @xlo.func def MakeMyType(): return MyType() ``` -------------------------------- ### Asynchronous GUI Initialization and Pane Attachment in xlOil Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/CustomGUI.rst This asynchronous function demonstrates how to initialize ExcelGUI without immediate connection and then asynchronously connect and attach a task pane. Ensure you maintain a reference to the ExcelGUI object to keep the UI connected. ```python async def make_gui(): # With connect=False the ctor does nothing excelui = xlo.ExcelGUI(xml=..., funcmap=..., connect=False) # The action happens when we call connect, which returns a awaitable future await excelui.connect() # We can also create the pane async by passing an awaitable but we have # to then pass the name explictly await excelui.attach_pane_async( name='TkPane', pane=Tk_thread().submit_async(TkTaskPane)) # We need to keep a reference to 'excelui' as deleting it disconnects the UI return excelui, pane ``` -------------------------------- ### Register and Handle Excel Events Source: https://context7.com/cunnane/xloil/llms.txt Demonstrates how to hook into Excel events like calculation completion, before print, and sheet changes, and register corresponding Python callback functions. ```python import xloil as xlo import datetime as dt def on_calc_finished(): """Called after each calculation""" wb = xlo.active_workbook() rng = wb["Sheet1"]["A1"] rng.value = f"Calc finished at: {dt.datetime.now()}" ``` ```python def on_before_print(wbName, cancel): """Called before printing - can cancel the print""" xlo.Range("B1").value = "Print cancelled for: " + wbName cancel.value = True # Cancel the print operation ``` ```python def on_sheet_change(worksheet, changed): """Called when cells change""" ws = xlo.worksheets[worksheet] ws["Z1"] = f"Changed: {changed.address()}" ``` ```python # Register event handlers xlo.event.AfterCalculate += on_calc_finished xlo.event.WorkbookBeforePrint += on_before_print xlo.event.SheetChange += on_sheet_change ``` ```python # Unregister when done # xlo.event.AfterCalculate -= on_calc_finished ``` -------------------------------- ### Dynamic Function Registration with Closure Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/Functions.rst Demonstrates dynamic function registration using a closure. A class 'Closure' is defined to maintain state across calls. Functions are appended to a list and then registered using xlo.register_functions. ```python class Closure: self._total = 0 def __call__(self, x): self._total += x return x funcs.append( xlo.func(fn=Closure(), name=f"dynamic1", register=False) ) xlo.register_functions(funcs, sys.modules[__name__]) ``` -------------------------------- ### Upload packages to PyPI Source: https://github.com/cunnane/xloil/blob/master/docs/source/Developer.rst Use twine to upload the built packages to the test or production PyPI repositories. ```bash cd \build\staging\pypackage # (Optional test) twine upload --repository-url https://test.pypi.org/legacy/ dist/* # The real thing twine upload dist/* ``` -------------------------------- ### Configure xlOil SQL Plugin Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_SQL/index.rst Add the SQL plugin to the xlOil configuration file. ```ini Plugins=["xlOil_SQL.dll"] ``` -------------------------------- ### Execute SQL Join Query Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_SQL/index.rst Join multiple data arrays using SQL syntax. ```excel =xloSql("SELECT table1.A, B, C FROM table1 ", { A B } , { A C } ) "INNER JOIN table2 " { Foo 1 } { Bar 2 } ) "ON table1.A == table2.A " { Baz 7 } { Foo 3 } ) ``` -------------------------------- ### Initialize NumPy Array Source: https://github.com/cunnane/xloil/blob/master/tests/ManualSheets/python/TestJupyterConnection.ipynb Create a NumPy array for use in calculations. ```python import numpy as np watch_var = np.array([6, 2, 3, 5]) ``` -------------------------------- ### Configure xloil Environment Variables and Path Source: https://github.com/cunnane/xloil/blob/master/tests/ManualSheets/python/TestJupyterConnection.ipynb Set environment variables and append to sys.path to configure the xloil environment, specifying build and library directories. ```python import sys import os soln_dir = os.path.join(os.getcwd(), r"..\..\.." "\") os.environ['XLOIL_BIN_DIR'] = os.path.join(soln_dir, r"build\x64\Debug") sys.path.append(os.path.join(soln_dir, r"libs\xlOil_Python\Package")) ``` -------------------------------- ### Create an xlOil XLL Addin Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/DistributingAddins.rst Use the 'xloil create' command to generate an XLL addin file and its associated INI file. This addin will attempt to load a Python script with the same base name. ```bash xloil create myaddin.xll ``` -------------------------------- ### Create a Qt Task Pane Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/CustomGUI.rst Inherit from QWidget to create a custom task pane. Use the attach_pane method to register the widget with Excel. ```python import xloil.gui.qtpy from qtpy.QtWidgets import QWidget class QtTaskPane(QWidget): def __init__(self): super().__init__() # Don't forget this! ... # some code to draw the widget def send_signal(self, int): ... # some code to emit a Qt signal excelui = xlo.create_gui(...) pane = excelui.attach_pane('MyPane', pane=QtTaskPane) # The widget is in the pane's `widget` attribute pane.widget.send_signal(3) ``` -------------------------------- ### Use Excel Application as Context Manager Source: https://context7.com/cunnane/xloil/llms.txt Shows how to manage the Excel application lifecycle using a context manager, ensuring automatic quitting. ```python # Using as context manager with xlo.Application() as app: app.visible = True wb = app.open("data.xlsx") # Work with workbook... # App automatically quit on exit ``` -------------------------------- ### Returning PIL Image from Function Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/TypeConversion.rst This function `ShowPic` demonstrates returning a PIL Image object. Importing `xloil.pillow` registers a custom return converter for `PIL.Image`. Macro permissions are required for this function. ```python import xloil.pillow from PIL import Image @xlo.func(macro=True) # macro permissions required def ShowPic(filename): return Image.open(filename) ``` -------------------------------- ### Create Custom Type Converters Source: https://context7.com/cunnane/xloil/llms.txt Shows how to define custom type converters for arguments and return values using the `@xlo.converter` decorator, enabling specialized data handling. ```python import xloil as xlo @xlo.converter() def arg_doubler(x): """Doubles the input value""" if isinstance(x, xlo.ExcelArray): x = x.to_numpy() return 2 * x ``` ```python @xlo.func def pyTestCustomConv(x: arg_doubler): """Input is automatically doubled""" return x ``` ```python # Call in Excel: =pyTestCustomConv(5) # Result: 10 ``` ```python @xlo.converter(typeof=bytes, register=True) class StrToBytes: """Converts strings to/from bytes""" def __init__(self, encoding='utf-8'): self._encoding = encoding def read(self, val): return val.encode(self._encoding) def write(self, val): return val.decode(self._encoding) ``` ```python @xlo.func def Pad(text: bytes, size: int) -> StrToBytes('utf-8'): return text.center(size) ``` -------------------------------- ### Set Button Images using loadImage Callback Source: https://github.com/cunnane/xloil/blob/master/docs/source/xlOil_Python/CustomGUI.rst Configure ribbon buttons to display images by specifying an 'image' attribute in the customUI XML and a corresponding 'loadImage' callback function that returns a PIL Image. ```xml ...