Using a macro to insert more macros - python

I've got some Python code that runs a query on a database that is read-only from my end and, which dumps me an Excel spreadsheet with relevant data that I want for visualization. I have several macros which process the data, create and edit graphs, and let me "filter" a couple different ways (each "filter" is several normal filters - convenient compared to manually selecting/clearing multiple filters).
My Python code generates a new Excel file daily stamped with the date. I would like to insert my suite of macros and run the setup ones automatically on each new file, rather than manually importing and executing them.
Is there a way to use a macro to insert several other macros, run some of them, and insert macro buttons or a dropdown box to run the filtering bit? If not, can it be done (or should it be done) from the Python side when it generates my Excel files?
Edit:
The python code was written by somebody else, and I do not know Python. It prints the data using:
with pd.ExcelWriter(filename) as writer:
df_merged_final.to_excel(writer, sheet_name='Final Data', index=False)

You can collect all your macros in a .bas file and import that whenever needed.
1) collect all your regular macros and put them in a module. You can even write one parent macro that calls all the other child macros, but they all need to be in this module;
2) export the module as a .bas file;
Then whenever you need the macros:
3) import the .bas file to your workbook;
4) your macros are now available in the ribbon of the developer tab which presents them as a dropdown list. If you used a parent macro, you can just click the parent macro to fire all the child macros.
This allows you to work in the source file itself and you can avoid copying large amounts of data to the clipboard. Also serves as a great backup of your most-used macros in case your master Excel file becomes corrupt.

Related

Write data with Python into existing excel file keeping it intact as much as possible

We have a rather complicated Excel based VBA Tool that shall be replaced by a proper Database and Python based application step by step.
There will be time of the transition between were the not yet completely ready Python tool and the already existing VBA solution will coexist.
To allow interoperability the Python tool must be able to export the database values into the Excel VBA Tool keeping it intact. Meaning that not only all VBA codes have to work as expected but also Shapes, Special Formats etc, Checkboxes etc. have to work after the export.
Currently a simple:
from openpyxl import load_workbook
wb = load_workbook(r'Tool.xlsm', keep_vba=True)
# Write some data i.e. (not required to destroy the file)
wb["SomeSheet!SomeCell"] = "SomeValue"
wb.save(r"Tool_filled.xlsm")
will destroy the file, i.e. shapes won't work, checkboxes neither. (The resulting file is only 5 MB from originally 8 MB, showing that something went quite wrong).
Is there a way to only modify only the data of an ExcelSheet keeping everything else intact/untouched?
As far I know an Excel Sheet are only zipped .xml files. So it should be possible to edit only the related sheets? Correct?
Is there a more comfortable way as writing everything from scratch to only modify the data of an existing Excel file?
Note: The solution has to work in Linux, so simple remote Excel calls are not an option.

Changing VBA code in hundreds of Excel files without opening every one of them

I have a data base of hundreds of submitted forms, every submitted form contains various modules with VBA code in them to process the data.
Each form file name starts with same unique prefix.
All of the forms are saved in our main global directory of documents.
Data from every form is logged into a log file.
VBA code within each forms allow me to change information in the form and send the updated information into the log.
Now because of the office 2019 being introduced, vb scripts in every form made in 2016 version is not working and I have to force change the code in every single form to make it compatible with 2019.
This mass change is not only required due to office version change but also required because I need to update log file with additional information contained within the forms cells which old VBA code does not process.
There are 4 VBA modules in every form file and scripts in every modules needs to be replaced with the new code.
Really don't know where to start, any ideas are much appreciated.
I have no idea what to try.
Expected result is that I have updated/new code for 4 macro modules currently exist in 100's of files which needs to be replaced over the old codes.. of excel files starting with a common unique prefix.
You can use VBA to modify VBA projects. For this, the "Trust access to the VBA project object model" checkbox must be ticked in the Trust Center/Macro Settings.
After that, open the VBA editor. Set a reference to "Microsoft Visual Basic for Applications Extensibility 5.3" (possibly the version is different for you, I don't know).
Now a couple of additional classes become available under the VBIDE library and those can be used to manipulate VBA projects programmatically. (I'm using this feature to export VBA modules for source control.)
There is no easy way to modify the text of the module, but you can try exporting, deleting and re-importing them to see if that already is enough:
Sub Test()
Dim vbcs As VBIDE.VBComponents
Dim vbc As VBIDE.VBComponent
Dim filename As String
Set vbcs = ActiveWorkbook.VBProject.VBComponents
For Each vbc In vbcs
Debug.Print vbc.name
If vbc.name = "The ones you want" Then
filename = GetFilenameFromModule(vbc)
vbc.Export filename
' you could modify the file contents now if needed
vbcs.Remove vbc
vbcs.Import filename
End If
Next vbc
End Sub
Private Function GetFilenameFromModule(vbc As VBIDE.VBComponent) As String
Select Case vbc.Type
Case vbext_ct_ClassModule, vbext_ct_Document:
GetFilenameFromModule = vbc.name & ".cls"
Case vbext_ct_MSForm:
GetFilenameFromModule = vbc.name & ".frm"
Case vbext_ct_StdModule:
GetFilenameFromModule = vbc.name & ".bas"
End Select
End Function
Be sure to check out the properties of the various objects in the debugger or object browser (F2), just to see what's available. I'm not sure how well documented all of that is, but it's versatile and stable.
To work with files in VBA easily, you can set a reference to the "Microsoft Scripting Runtime" library and use the FileSystemObject.

Python: hide Open File Dialog when running Excel macro

I'm writing a Python script to automate a process that uses Excel macros to format files to input into a different program later on. I'm a bit new to Python and completely new to VBA, but I think I have the steps down.
So far I have this to run the macro itself (with help from other SO posts):
xl = win32com.client.DispatchEx('Excel.Application')
xlpath = os.path.expanduser(xlfile)
wb = xl.Workbooks.Open(Filename=xlpath, ReadOnly=1)
xl.Run("my_macro")
At this point the macro runs and calls Application.GetOpenFilename() to open a dialog for the user to choose the file to be formatted, which is going to be different for each macro.
Basically my user is going to have different initial data to format each time they run my script. At the beginning I want them to choose the files that they need formatted and then I'll save those file paths. Then I want to plug those file paths into the macro from Python instead of opening the dialog in Excel.
Is there a way to do this directly by changing the macro? If not, will I need to rewrite the macro in Python with one of the modules out there for driving Excel?
It looks like I can call xl.Run("my_macro") with parameters so I just have to figure out how the macro reads in those parameters so once I pass in the paths it can just open the files without the dialog.
xl.Run("my_macro", path1, path2)
https://stackoverflow.com/a/16740500/3788802

Module that can help control excel from within python application anything more needed than pywin32?

I have a viewer I built using WXPython. The viewer is basically a browser (built on IE wx.lib.iewin) that loads the txt or htm files I have in a directory and then lets me move through the files sequentially. Instead of having to go to the directory to select the next file to view the viewer/browser has a next button that loads the next file in the queue.
I want to be able to add a new feature that allows me to highlight some text that is visible in the browser and then push a button and have that text passed into a cell in excel.
Lots of things are going to have to happen like I need to be able to find and start a new instance of excel. I need to be able to add a new worksheet and pass some values to populate cells on the worksheet based on the file I am looking at and then if I want to collect some data from the file I want to be able to highlight the data in the viewer and then press a button on the viewer and have the data passed to excel.
I think I am going to start with PyWin32 but I am wondering if there is something else I need but I don't know enough to look for it.
If someone knows of an example where text was piped from a Python application to excel under the users control I would appreciate a pointer in that direction. It is easy enough I think to do this going from the application to a file that gets created (but not displayed) but I am hoping to go from the browser to the excel file so that the user can evaluate their work in progress.
I'd recomend using one of the python excel modules like python-excel.
It works on any OS, and without any other Excel application installed.
http://www.python-excel.org/
Code would look somehting liek this to write to a new xls document, slightly different to open an existing.
import xlwt
wbk = xlwt.Workbook()
sheet = wbk.add_sheet('sheet 1')
# indexing is zero based, row then column
sheet.write(0,1,'test text')
wbk.save('test.xls')
Hopefully this can get you on the right path, then you'll be able to post more specific questions if you run into problems.
Note: Another option is openpyxl:
http://packages.python.org/openpyxl/tutorial.html
If you're using wxPython (which I assume you are due to the tag), you should look at XLSGrid: http://www.blog.pythonlibrary.org/2011/08/20/wxpython-new-widget-announced-xlsgrid/
If you just want to work with Excel, I would recommend xlwt or xlrd, although you can use PyWin32 to work with it too via COM: http://www.blog.pythonlibrary.org/2010/07/16/python-and-microsoft-office-using-pywin32/

Is it possible create/edit an excel macro from python?

I'm currently working on a project that requires me to write a (seemingly endless) series of macros to reproduce pivot tables designed by one of our Analysts. The details change, but the code is largely the same from example to example.
I would like to programmaticly generate the vba code based on a handful of options and then add the macro to the given worksheet. Is it possible to create an excel macro with python using win32com or other? Is it possible to create an excel macro from another excel macro? Any other ideas?
Project Background, I have a python script that does the following:
pulls Google Analytic data
does various analysis
writes the results to excel
triggers a pre-written macro to turn the data into a beautifully formatted pivot table
emails it off to people who probably don't actually read it
Yes you can create an Excel macro with another Excel macro. For that to work, you need to tell Excel to Trust Access to the VBA Project Object model. (The setting is found in Macro Options in the Trust Center.) I don't know if you can do it from Python, but if you can, you probably also need to tell Excel it is ok.
For ease of coding, if you are doing this in Excel, add a reference to Micorsoft Visual Basic for Applications Extensibility.
You might also want to check out MZ-Tools 3.0 I find it very helpful for adding default\common code to a project.
On the other hand, your project sounds ripe for code reuse. If the common pivot table code is in one class/module, it is really easy to copy it from one open Excel project to another. (Just click and drag in the Project Explorer window.) You can also export it out to a text file and import it back in to another project later.

Categories