2

I'm a heavy VBA user that when has the chance to do a little project in python it's like going from hell to haven when it comes to programming itself. Still, I know that my users want reports in excel (for good reasons) and I'm just not ready to give up how amazingly easy is to deploy a new version in excel: just save a new workbook with new version name.

These workbooks have something like 30 users from different departments/countries. I have a new version at least once a week and often 2/3 in the same day. Deployment must be practical.

Trying to combine the best of both worlds I came up with the following question:

https://stackoverflow.com/questions/39175926/python-com-server-with-vba-late-biding-skip-win-register-no-admin-rights

However what gave me hopes was the 'Way 2' here:

https://stackoverflow.com/a/9880276/4797660

which led me here:

https://setuptools.readthedocs.io/en/latest/setuptools.html

As I'm going down this rabbit hole I thought if it wouldn't be wise to ask around for other that have tried something similar. What I'm afraid is this will be one these situation with so many extra complications that, even after the initial learning curve, the costs will outrun the benefits.

Any words on the risks I'm taking by trying to come up with a very practical build-in-python-use-it-in-VBA approach?

The user interacts heavy with the workbook via worksheet events (like click on this data to see details). That basically turn the workbook into a hybrid of report and application. Also need things like change cell format and print formula to a cell. Often a pivot will be put on top of the data and the user will play with it. This all adds up to the impression that I will always need a VBA layer that would call the python objects.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
BuckTurgidson
  • 31
  • 1
  • 4
  • "how amazingly easy is to deploy a new version in excel" It might be easy to save a new version, but how hard is it to make sure everyone keeps up to date? You'll see plenty of horror stories about trying to manage who is on what version. – jpmc26 Aug 29 '16 at 01:31
  • @jpmc26. Indeed this statement cannot be generalized. It's true in my case. – BuckTurgidson Aug 29 '16 at 05:31
  • Deploying a compiled executable or a python script is definitely as simple as deploying an Excel document, once the target machine contains the required run time environment. However, it seems you want to use Python from VBA by COM??? Is that really necessary? That is what it makes harder in your case. Can't you just run your Python script in a separate process by utilizing VBA's `Shell` command and implement the I/O through files? – Doc Brown Aug 29 '16 at 05:55
  • @jpmc26: if the deployment of new Excel VBA programs is simple or not depends heavily on if there is a clear separation between the program and user's data, so the first one can be updated without overwriting the second. I guess the OP has made this separation, otherwise he would already be in big trouble. – Doc Brown Aug 29 '16 at 05:59
  • As an alternative which works seemlessly with Excel, does not need any messing around with the registry, and can be used for making single-file deployments: you might consider to use [Excel-DNA](https://exceldna.codeplex.com/) for creating an Excel-Addin, and combine this with [IronPython](http://ironpython.net/), if it really must be Python. I used this only with VB.NET and C# by myself, however. – Doc Brown Aug 29 '16 at 06:09
  • @DocBrown. Want is to use the python-built object in VBA. Just printing the excel file with the data would mean give up on-click events. COM is not a solution because of the admin rights. Idea now is excel self loaded add-in. I need the self loaded mostly while in development. – BuckTurgidson Aug 29 '16 at 06:10
  • @BuckTurgidson: then Excel-DNA is probably what you are looking for. It might be easier, however, to start with a VB.NET add-in before you integrate IronPython into this. – Doc Brown Aug 29 '16 at 06:14
  • @Doc Brow. Python is mostly because I'm used to and because I really care for quick development. It feels now that steeping into VB.NET first is the natural path. – BuckTurgidson Aug 29 '16 at 07:46
  • "Any words on the risks I'm taking" - develop a demo/proof-of-concept first and try to deploy that to a beta tester customer. If he has trouble due to admin rights, DLLs, Excel version, etc, then you'll know before you spend any more time on it. – Brandin Aug 29 '16 at 11:44
  • @DocBrown Of course, but I didn't think this was possible with VBA. I even have [an existing question](http://stackoverflow.com/q/16800911/1394393) about doing that with Access that never received a real answer. – jpmc26 Aug 29 '16 at 13:40
  • @jpmc26: not sure I understand what you are trying to tell me. What do you mean by *"I didn't think this was possible with VBA"* - I did not suggest anything which might be possible "with VBA". My suggestion is more a full replacement for VBA code. However, Excel-DNA will also allow to write .NET functions which can be called from VBA, but I am under the impression that is not what OP is really after. For Access, however, I don't know any comparable solution. – Doc Brown Aug 29 '16 at 13:47
  • @DocBrown "if the deployment of new Excel VBA programs is simple or not depends heavily on if there is a clear separation between the program and user's data ... I guess the OP has made this separation ..." I was trying to tell you why I didn't consider this a possibility. As far as I'm aware, VBA code must be embedded in the user's data file. This is even what the OP describes doing in the question ("save a new workbook with a new version name"). So I think your assumption is unwarranted; I don't know how the OP is overcoming this difficulty. – jpmc26 Aug 29 '16 at 13:54
  • @BuckTurgidson I have a clarification I'd like to ask for. Are your users *entering* data in the Excels you give them, or could you just *generate* an Excel document as output? – jpmc26 Aug 29 '16 at 14:01
  • 1
    @jpmc26: ok, now I got you. One can perfectly write VBA programs as part of one Excel document, and keep the user's data in a second document. The VBA macro then can create reports as a third document. All that is pretty simple, one has just to care for this separation, no magic involved. This is mandatory if you ever want to be able to deploy a version 2.0 after version 1.0. Actually this is what I always told people in the first 30 minutes of my introductory VBA lessons ;-) – Doc Brown Aug 29 '16 at 14:27
  • @DocBrown Sensible. It completely defeats the purpose of even having the ability to embed them, though, which just goes to show it was a bad design decision. lol. – jpmc26 Aug 29 '16 at 16:56
  • @jpmc26: I guess at the time when VBA came up, the decision did not look so bad as it might look today. And the deep integration of VBA into Excel has still its value (for example, I often use the macro recorder to find out how to do some things programmatically). I have written lots of VBA programs with embedded sheets as templates in the past, which can be done directly in Excel with almost no overhead. A similar solution for an addin needs always some more programming effort (I did this, too, so I know what I am talking about). – Doc Brown Aug 29 '16 at 17:34
  • You can try something to create the excel files for the users like: https://openpyxl.readthedocs.io/en/default/#. – JeffO Aug 29 '16 at 18:51
  • @jpmc26. Most of time users read and 'click to show details' on the data. Sometimes they can enter data and push a push a button edit/saves/send data. – BuckTurgidson Aug 29 '16 at 20:28

2 Answers2

4

If it is more important to you to use Python as a language, and not because you need the full stack of available modules for CPython, maybe a combination of Excel-DNA and IronPython maybe an option for you.

Excel-DNA will allow you to develop Excel addins using any .NET language, which don't need any registration or installation on the target machine. The only prerequisite is the specific .NET framework version installed there, which is typically the case on most modern Windows systems. Moreover, Excel-DNA includes a packing tool to combine all files and DLLs needed to a single file. The result will be an XLL file which can be as easily deployed as an XLSM Excel VBA macro file.

IronPython, as you might know, is a .NET implementation of Python, it will allow you to produce .NET assemblies written in Python. So far, I used the Excel-DNA framework only with VB.NET and C#, not with IronPython, but in principle when you bind a .NET assembly to Excel-DNA, the latter will not be aware in which language the assemblies' source code was written. The IronPython docs give some hints how to use it for creating assemblies which can be loaded from other .NET assemblies like the Excel-DNA framework, however, there might be some obstacles to come around. You have to try it out by yourself. I would recommend, however, to start with VB.NET addin first before you switch to Python.

Doc Brown
  • 199,015
  • 33
  • 367
  • 565
1

You can keep it loose with Python scripts and call them with what I call a gateway class. So called gateway because it opens the rich world of the Python ecosystem to the Excel VBA Developer http://exceldevelopmentplatform.blogspot.com/2018/06/python-vba-curve-building.html

In fact, on my blog June 2018 is Python month where I show off Python features and make them available to Excel VBA Developers to expand their horizons.

I reproduce the code my from my article here some code which gives VBA developers access to Python's CubicSpline class (as an example of a cool Python feature that a VBA dev could use instead of coding their own).

import numpy as np
from scipy.interpolate import CubicSpline

class PythonCubicSpline(Object):

    _reg_clsid_ = "{F48006B8-42B5-4D89-8D3C-C3C3E5E24C8D}"
    _reg_progid_= 'SciPyInVBA.PythonCubicSpline'
    _public_methods_ = ['Initialize','Interpolate']

    def Initialize(self, x1, y1):
        # calculate natural cubic spline polynomials
        x = np.Array(x1)
        y = np.Array(y1)

        self.baseCubicSpline = CubicSpline(x,y,bc_type='natural')
        return str(self.baseCubicSpline)

    def interpolate(self, x):
        return self.baseCubicSpline(x).tolist()

if __name__=='__main__':
    Print ("Registering COM server...")
    Import win32com.server.register
    win32com.server.register.UseCommandLine (PythonCubicSpline)

and some calling Excel code

Option Explicit

Sub TestPythonCubicSpline()

    Dim cubSpline As Object
    Set cubSpline = CreateObject("SciPyInVBA.PythonCubicSpline")

    Call cubSpline.Initialize(Array(0, 1, 2, 3, 4, 5), Array(12, 14, 22, 39, 58, 77))

    Debug.Print cubSpline.Interpolate(1.25) '* passing single,  outputs 15.203125

    Debug.Print Join(cubSpline.Interpolate(Array(1.25, 1.5)), ";") '# passing an array, outputs 15.203125;16.875

End Sub
S Meaden
  • 179
  • 7