When working on a project it's sensible to organize your Python code into packages. Using Python packages can make your code base easier to navigate and use by keeping everything logically organized.
PyXLL can import Python packages in the same way it imports Python modules, so there's no reason not to use packages with PyXLL.
When a package is imported, any Excel functions, macros or menus from any sub-modules (including those in sub-packages) are registered by PyXLL when they are imported. For example, you might have a package structure as follows:
mypackage
├── __init__.py
├── module1.py
└── subpackage
├── __init__.py
└── moudule2.py
Any Excel functions, menus or macros in module1.py and module2.py will be registered by PyXLL when they are imported. In order for the modules to be imported they must be imported by the packages __init__.py files, for example:
# mypackage/__init__.py
from . import module1
from . import subpackage
# mypackage/subpackage/__init__.py
from . import module2
The individual modules don't all need to be added to your pyxll.cfg file, adding just the top level package is enough.
# pyxll.cfg
[PYXLL]
modules =
mypackage
Avoiding Naming Conflicts
When a function or macro is exposed to Excel from a package, the name used is still just the function name without the package namespace. For example, in the above package if you have a function
# mypackage/subpackage/module2.py
@xl_func
def func1(...):
return ...
This function will still be exposed to Excel simply as "=func1()". If have multiple functions with the same name in different packages they will conflict. To resolve this you will need to supply a different name using the "name" argument to @xl_func. For example,
# mypackage/subpackage/module2.py
@xl_func(name="module2.func1")
def func1(...):
return ...
Excel function names can include "." and so that can be convenient way to namespace your functions in Excel if you need to. This function would now be called from Excel as "=module2.func1()".
Reloading Packages
When reloading PyXLL, by default only the modules listed in the config file will be reloaded. This means that in our example when reloading only the package "mypackage" would be reloaded - and that means only the "mypackage.__init__.py" file, not the modules or sub-packages contained within it.
For PyXLL to reload the modules and sub-packages you need to enable PyXLL's "deep reloading" feature. When this is enabled PyXLL will track all the dependencies of the modules and packages listed in the config file and also reload those. In our example, mypackage has mypackage.module1 and mypackage.subpackage as dependencies (because they are imported by it) and so with deep reloading enabled PyXLL will also reload those.
# pyxll.cfg
[PYXLL]
deep_reload = 1
You can read more about deep reloading in the user guide here.