PyXLL The Python Excel Add-In
  • Product
    • Features
    • Get Started
    • Request Demo
    • Download
  • Pricing
  • Resources
    • Documentation
    • Blog
    • Videos
    • FAQ
    • Learn Python
    • Customer Portal
    • About Us
  • Support
    • Documentation
    • Videos
    • FAQ
    • Contact Us
  • Contact Us
Table of Contents
  • PyXLL Documentation
  • Introduction to PyXLL
  • User Guide
    • Installing PyXLL
    • Configuring PyXLL
    • Worksheet Functions
    • Macro Functions
    • Real Time Data
    • Cell Formatting
    • Charts and Plotting
    • Custom Task Panes
    • ActiveX Controls
    • Using Pandas in Excel
    • Customizing the Ribbon
    • Context Menu Functions
    • Working with Tables
    • Python as a VBA Replacement
    • Menu Functions
    • Reloading and Rebinding
    • Error Handling
    • Deploying your add-in
      • Sharing everything on a network drive
      • Using a standalone zip file
      • Building an installer
      • Using a common pyxll.cfg file
      • Using a startup script to install and update Python code
      • Deploying the Python Environment
      • Adding the PyXLL add-in to Excel
      • Setuptools Entry Points
    • Workbook Metadata
  • Video Guides and Tutorials
  • API Reference
  • What’s new in PyXLL 5
  • Changelog
Close

Deploying your add-in¶

Everything needed to run your Python code using the PyXLL add-in can be packaged together and deployed to other users of your organization.

PyXLL is licensed per-user so you should check your license covers all the users of the add-in. If you need to add more users to your license you can do so using the customer portal, or contact us if you are not sure.

Warning

Redistribution of the PyXLL add-in to unlicensed users is not permitted by the Software License Agreement.

For the add-in to work your end users will need to have the following. Each can be pre-configured and packaged so that the end user doesn’t need to install each individually or do any configuration themselves:

  1. Your Python code

  2. A Python environment with any dependencies installed

  3. The PyXLL add-in, configured and loaded in Excel

One of the benefits of using PyXLL is that the code is separated from the Excel workbooks so that updates to the code can be deployed without having to change each workbook that depends on it.

There are various ways to make the items listed above available to your end users. Which methods you choose will depend on your specific use case and requirements. It’s quite usual to end up using a combination of the methods described below.

  • Sharing everything on a network drive

  • Using a standalone zip file

  • Building an installer

  • Using a common pyxll.cfg file

  • Using a startup script to install and update Python code

  • Deploying the Python Environment

  • Adding the PyXLL add-in to Excel

  • Setuptools Entry Points

    • modules entry point

    • ribbon entry point

See the video below to learn about how you can deploy your PyXLL add-in to other licensed members of your organization, even if they are not Python users.
How to deploy a PyXLL based add-in

Sharing everything on a network drive¶

This is the simplest option as it allows your Python code to be deployed centrally, ensuring that all users see the same code at all times.

As long as a user can read from the network drive, PyXLL can be configured to read Python modules from there. This ensures that you don’t need to copy code around and that all users are always referencing the same version of your code.

The PyXLL configuration can be shared by using the external_config option in the pyxll.cfg file (see Using a common pyxll.cfg file). You can list multiple external configs which will get merged together when PyXLL loads.

The PyXLL config file itself can also be on a network drive. The environment variable PYXLL_CONFIG_FILE can be set to tell PyXLL to load a config file from somewhere other than the default location. You can use environment variables inside the config file so that logging gets written to the user’s local storage.

When deploying code on a network drive you will want to make the folder read-only to your users to ensure no accidental updates occur.

To update the Python code, rather than updating in-place it is good practice to create a new folder with the updated code and then change the pythonpath in the shared config file to that new folder. This way if there are any problems then you can quickly revert to the previous folder, and it also avoids problems with certain files (e.g. dll and pyd files) becoming locked while users have then open.

A typical structure for this shared folder would be (with the folder names changed to suit your requirements):

  • modules-{version}

    The folder containing your Python code

  • python-{version}

    (Optional) Folder containing your Python environment

  • shared_pyxll.cfg

    This would specify pythonpath = ./modules-{version}, your modules list, any other shared settings, and optionally executable = .\python-{version}\pythonw.exe if you are including the Python environment on the network drive.

In your main pyxll.cfg file you would include the shared_pyxll.cfg file using external_config = X:\network\folders\pyxll\shared_pyxll.cfg.

You would choose whether or not to include the Python environment on the shared folder or not depending on whether or not each user would already have a suitable local Python environment and how fast your network drive is. Loading Python from a slow network drive can slow down starting Excel, in which case one of the options below may be more suitable.

To install the PyXLL add-in you can either load the pyxll.xll add-in manually into Excel, or your could script it using the pyxll activate command (see Adding the PyXLL add-in to Excel).

Using a standalone zip file¶

Similarly to putting everything on a network drive, as above, you can combine everything into a single zip archive for distribution to your users. You can include everything, including a Python environment, and pre-configure PyXLL to reference it using a relative path.

To install the PyXLL add-in you would unzip the archive on the PC where you want it to be installed and then load the PyXLL add-in in Excel. This can be scripted, and you can script the step of adding PyXLL to Excel using the pyxll activate command (see Adding the PyXLL add-in to Excel).

Once installed, updates can be made using a Startup Script. See Using a startup script to install and update Python code for more details about that.

A typical structure for this zip file would be (changing the folder names to suit your requirements):

  • modules

    The folder containing your Python code

  • python

    Folder containing your Python environment

  • pyxll.xll

    The PyXLL add-in

  • pyxll.cfg

    This would specify everything relative to the location of this file. For example, pythonpath = .\modules and executable = .\python\pythonw.exe.

Once you have a zip file containing the above you could use a batch script to do the installation. The script would do the following:

  • Copy and unzip your_pyxll_archive.zip to C:\Your\Local\PyXLL\Install

  • Run C:\Your\Local\PyXLL\Install\python\python.exe -m pyxll activate --non-interactive C:\Your\Local\PyXLL\Install\pyxll.xll

This script could be run directly by your end users to install the add-in, or pushed out by your systems team or IT administrators. It could even be configured to run each time the user logs in.

Building an installer¶

If you prefer to build an installer or MSI instead of using a zip file and script as above then that is also possible. Some organizations prefer this method as they already have mechanisms for pushing out installers to users’ PCs.

As with the zip file approach above, the Python runtime can be bundled alongside PyXLL and your Python code into a single standalone installer.

For detailed instructions and an example project for building an MSI installer, see the pyxll-installer project on GitHub.

Using a common pyxll.cfg file¶

The PyXLL config be shared so that each user gets the same configuration, and so updates to the config can be made once rather than on each PC. This is done by setting the external_config option in the pyxll.cfg file.

Each user still has their own pyxll.cfg file with any settings specific to them (if any), but they also use the external_config option to source in one or more shared configs.

The external config can be a file on a network drive or a URL.

[PYXLL]
external_config = https://intranet/pyxll/pyxll-shared.cfg

If more than one external config is required the external_config setting accepts a list of files and URLs.

If it is not desirable for each user to have their own pyxll.cfg file then the environment variable PYXLL_CONFIG_FILE can be set to tell PyXLL where to load the config from. This could be a path on a network drive or a URL.

When using a shared config typically you don’t want the log file to be written to the same place for every user. You can use environment variables in the config file to avoid this, eg

[LOG]
path = %(USERPROFILE)s/pyxll/logs

See Environment Variables for more details.

Using a startup script to install and update Python code¶

Importing Python code from a network drive can have some disadvantages. It requires a fast network, and even then it can be slow to import the modules. It may also be against your coroprate IT policy to deploy code via a network drive because it lacks sufficient control, or it just may not suit your deployment needs.

Using a startup script you can check what version of your Python code is currently deployed and download the latest if necessary. Once downloaded the code is on the local PC and so importing it will be fast. When updates are needed the script will detect there’s a newer version of the code available and download it.

Such a script might look something like this:

SET VERSION=v1
SET PYTHON_FOLDER=.\python-code-%VERSION%

REM No need to download anything if we already have the latest
IF EXIST %PYTHON_FOLDER% THEN GOTO END

REM Download and unzip the latest code
wget https://intranet/pyxll/python-code-%VERSION%.tar.gz
tar -xzf python-code-%VERSION%.tar.gz --directory %PYTHON_FOLDER%

ECHO Latest code has been downloaded to .\python-code-%VERSION%
:END

The above script is just an illustration and your script would be different depending on your needs. It could also be a Powershell script rather than a plain batch script.

To get this script to run when Excel starts we use the startup_script option in the pyxll.cfg file. This is set to the the path of the script to run, or it can be a URL. By using a URL (or a location on a network drive) whenever we want to deploy a different version of the code to all of our users we only have to update the version number in the script.

[PYXLL]
startup_script = https://intranet/pyxll/startup-script.cmd

Now the script runs when Excel starts, but the code downloaded isn’t on our Python Path and so won’t be able to be imported. Because we’re using a different folder for each version of the code we can’t hard-code the path in our pyxll.cfg file.

Within a startup script run by PyXLL you can run various commands, including getting and setting PyXLL options. There’s a command pyxll-set-option that we can use to set the pythonpath option to the correct folder:

SET VERSION=v1
SET PYTHON_FOLDER=.\python-code-%VERSION%
ECHO pyxll-set-option PYTHON pythonpath %PYTHON_FOLDER%

The pyxll-set-option command is run by echoing it from the batch script. PyXLL sees this in the output from the script and updates the pythonpath option. Calling pyxll-set-option for a multi-line option like pythonpath appends to it rather than replacing it.

There are several other commands available from a startup script. See Startup Script for more details.

Deploying the Python Environment¶

The Python environment and many of the Python packages your code depends on are likely to change less often than your main Python code. They do still need to be available to PyXLL for it to work however.

This doesn’t mean that Python actually needs to be installed on the local PC.

PyXLL can be configured to use any Python environment as long as it is accessible by the user. This means you can take a Python environment and copy it to a network drive and have PyXLL reference it from there. For example, where below X: is a mapped network drive:

[PYTHON]
executable = X:\PyXLL\Python\pythonw.exe

As long as the Python environment on the network drive is complete, this will work fine.

A very useful tool for creating a Python environment suitable for being relocated to a network drive is conda-pack.

Note, using a venv doesn’t create a complete Python environment and still requires the base Python install and so cannot be used in this way.

Referencing the Python environment from a network drive will not be as fast to load as if it was installed on the local PC. Another option is to use the startup_script option and copy a Python environment locally on demand when Excel starts.

A startup script that downloads a Python environment would look something along the lines of the following:

SET VERSION=v1
SET PYTHON_ENV=.\python37-%VERSION%

REM No need to download anything if we already have the latest
IF EXIST %PYTHON_ENV% THEN GOTO DONE

REM Download and unzip the Python environment
wget https://intranet/pyxll/python37-%VERSION%.tar.gz
tar -xzf python37-%PYTHON_ENV%.tar.gz --directory %PYTHON_ENV%

ECHO Latest Python environment has been downloaded to .\python37-%VERSION%
:DONE

REM Set the PyXLL executable option
ECHO pyxll-set-option PYTHON executable %PYTHON_ENV%\pythonw.exe

Adding the PyXLL add-in to Excel¶

Once you have made your Python code and Python environment available to your end user, either by copying them to the local PC or by making them available on the network drive, you will need to add the PyXLL add-in so that it gets loaded each time Excel starts.

This can either be done manually, if the end user is comfortable managing their own Excel add-ins, or it can be scripted for them.

To install the PyXLL add-in from a script you can use the pyxll activate sub-command. The activate sub-command installs the PyXLL Excel add-in into Excel so that it is loaded whenever Excel starts.

When using the pyxll command from a specific Python environment, rather than the system default or currently active environment, it can be easier to use python -m pyxll instead of running the pyxll command directly. For example, if you have the PyXLL add-in copied locally to C:\PyXLL\pyxll.xll and Python copied locally as C:\PyXLL\python\python.exe you would run:

> C:\PyXLL\python\python.exe -m pyxll activate --non-interactive C:\PyXLL\pyxll.xll

The --non-interactive switch prevents the pyxll activate command from asking the user for input or confirmation which makes it suitable to be called from a script.

Setuptools Entry Points¶

When distributing Python code it is usual to package it up into a wheel file using setuptools. This allows consumers of your package to install it easily using pip (the Python package manager).

You can distribute a Python package containing PyXLL functionality in the same way. To avoid the end user of your package from having to manually configure their pyxll.cfg file, PyXLL looks for its entry points in any installed packages.

The entry points are configured in your setup.py file used to build your package. PyXLL supports two entry points, pyxll.modules and pyxll.ribbon.

A simple setup.py file to build a package called your_package might look as follows:

from setuptools import setup, find_packages

setup(
    name="your_package",
    description="Your package description",
    version="0.0.1",
    packages=find_packages(),
entry_points={
"pyxll": [
"modules = your_package:pyxll_modules",
"ribbon = your_package:pyxll_ribbon"
]
}
)
setup.py¶

To build a wheel using your setup.py file you run python setup.py bdist_wheel.

The user of your package would install the wheel by running pip install <wheel file>.

The entry points listed in this setup.py file are your_package:pyxll_modules for the pyxll/modules entry point and your_package:pyxll_ribbon for the pyxll/ribbon entry point.

Each entry point is a reference to a function. It’s these functions that PyXLL will call to configure itself to load your package automatically without the consumer of your package having to modify their pyxll.cfg file.

modules entry point¶

The modules entry point is a function that returns a list of module names for PyXLL to import when it loads.

In the above your_package example, suppose your_package contained two sub-modules your_package.xlfuncs and your_package.xlmacros that you want to be loaded when PyXLL starts. To make that happen you would write the your_package.pyxll_modules entry point function return both packages.

def pyxll_modules():
    """entry point referenced in setup.py"""
    return [
        "your_package.xlfuncs",
        "your_package.xlmacros",
    ]
your_package/__init__.py¶

This is of course just an example. The entry point function could be in any package (including a subpackage) that you configure in your setup.py file.

ribbon entry point¶

The ribbon entry point can be used to add ribbon controls to the Excel ribbon in addition to whatever ribbon controls are configured in the pyxll.cfg file.

The ribbon entry point function should return either a single ribbon xml resource or a list of ribbon xml resources. These will be merged with any other ribbon files loaded and combined to create the custom ribbon UI in Excel.

See Customizing the Ribbon for the specifics of how to create a ribbon xml file.

In the above your_package example, suppose you had also included a “ribbon.xml” resource in the wheel and you wanted to add that to the Excel ribbon. Your ribbon entry point would load the XML data from the resource (or it could load it from a file) and return that for PyXLL to use when building the ribbon.

import pkg_resources

def pyxll_ribbon():
    """entry point referenced in setup.py"""
    # Load the XML resource
    ribbon_xml = pkg_resources.resource_string(__name__, "ribbon.xml")

    # Return the ribbon XML resource for PyXLL to load
    return ribbon_xml
your_package/__init__.py¶

If you are using files instead of package resources then you can also tell PyXLL the filename of the XML file. If you have images referenced in your ribbon xml using relative paths then providing the filename will ensure that PyXLL can load the images relative to the correct path.

import os

def pyxll_ribbon():
    """entry point referenced in setup.py"""
    # Get the ribbon XML filename
    ribbon_file = os.path.join(os.path.dirname(__file__), "ribbon.xml")

    # Load the xml data
    with open(ribbon_file) as fh:
        ribbon_xml = fh.read()

    # Return the ribbon XML resource with its file name for PyXLL to load
    return (ribbon_file, ribbon_xml)
your_package/__init__.py¶

When using the load_image function as your image loaded in the ribbon xml file, images can be referenced either by filename or as a package resource name if you are building them into your package.

If you have multiple ribbon resources then the pyxll.ribbon entry point function may return a list of resources or a list of (filename, resource) tuples.

Warning

If your Python packages are on a network drive it can be slow to look for entry points, which may result in slow start times for Excel.

You can prevent PyXLL from looking for entry points by setting the following in your pyxll.cfg file:

[PYXLL]
ignore_entry_points = 1
« Error Handling
Workbook Metadata »
  • Home
  • Product
  • Features
  • Documentation
  • Download
  • Pricing
  • Support
  • Documentation
  • Videos
  • FAQ
  • Learn Python
  • Contact Us
  • About
  • About Us
  • Legal
  • Blog
© Copyright PyXLL Ltd