Run a line of VBA code from within Python using win32com - python

Rather than running a macro already built into an Excel spreasheet, I would like to run a single line of code. For example:
import os
import win32com.client
xl = win32com.client.Dispatch("Excel.Application")
xl.Workbooks.Open(Filename='foo.xlsx')
xl.Application.Run("excelsheet.xlsm!modulename.macroname") # what I can do
xl.Application.RunLine('ThisWorkbook.ContentTypeProperties("Project Title") = "Category A"') # this is what I want to do instead
xl.Application.Save()
xl.Application.Quit()
del xl

Related

Click CommandButton with win32com

I have a Form with a CommandButton in my excel sheet and I would like to click it with my python script.
Things that do NOT work:
import win32com.client
xl = win32com.client.Dispatch('Excel.Application')
xl.Workbooks.Open(file)
xl.Application.Run('CommandButton.1')
I am guessing this does not work as it is not a macro
import win32com.client
xl = win32com.client.Dispatch('Excel.Application')
xl.Workbooks.Open(file)
xl.DoCmd.OpenForms('CommandButton.1')
xl.Forms('CommandButton.1').CommandButton_Click()
This did not work because DoCmd is for Access and does not apply to Excel.

How to run Excel VBA / Macro from Python

I am trying to run a VBA Macro in an xlsm workbook using python 3.7 in Spyder. This workbook has two worksheets.
The code that I have currently runs and saves the new file with no problems, however it is not triggering the VBA like it should.
I know this macro works because if I manually click the button in Excel, it works just fine.
Could someone assist with this? I checked the Macro Settings under the Trust Center and all macros are enabled so I do not think it is a permissions issue, however I am not an admin on this pc.
The code is below:
import os
import win32com.client
xl = win32com.client.Dispatch("Excel.Application")
wb = xl.Workbooks.Open("Z:\FolderName\FolderName2\FileName.xlsm")
xl.Application.Run("MacroName")
wb.SaveAs("Z:\FolderName\FolderName2\FileName1.xlsm")
wb.Close()
xl.Quit()
This can be done easily through xlwings. Once I switched to that library then I was able to quickly get this script working.
First make sure you have your All.xlsm file in your current working or in your User/Documents(Sometimes it working from yourDocuments directory and sometimes not, so better to have in both)
pass your macro name along with the file name that contains the macro you can make change to Parameters like ReadOnly or Savechanges according to your requirement
And be make sure to deleta xl object after each run
import win32com.client
xl =win32com.client.dynamic.Dispatch('Excel.Application')
xl.Workbooks.Open(Filename = XYZ.xls, ReadOnly= 1)
xl.Application.Run('All.xlsm!yourmacroname')
xl.Workbooks(1).Close(SaveChanges=1)
xl.Application.Quit()
del xl
Running Excel Macro from Python
To Run a Excel Marcro from python, You don't need almost nothing. Below a script that does the job. The advantage of Updating data from a macro inside Excel is that you immediatly see the result. You don't have to save or close the workbook first. I use this methode to update real-time stock quotes. It is fast and stable.
This is just an example, but you can do anything with macros inside Excel.
from os import system, path
import win32com.client as win32
from time import sleep
def isWorkbookOpen(xlPath, xlFileName):
SeachXl = xlPath + "~$" + xlFileName
if path.exists(SeachXl):
return True
else:
return False
def xlRunMacro(macroLink):
PathFile = macroLink[0]
xlMacro = macroLink[1]
isLinkReady = False
# Create the link with the open existing workbook
win32.pythoncom.CoInitialize()
xl = win32.Dispatch("Excel.Application")
try:
wb = win32.GetObject(PathFile)
isLinkReady = True
except:
NoteToAdd = 'Can not create the link with ' + PathFile
print(NoteToAdd)
if isLinkReady:
# If the link with the workbook exist, then run the Excel macro
try:
xl.Application.Run(xlMacro)
except:
NoteToAdd = 'Running Excel Macro ' + xlMacro + ' failed !!!'
print(NoteToAdd)
del xl
def mainProgam(macroSettings):
FullMacroLink = []
PathFile = macroSettings[0] + macroSettings[1]
FullMacroLink.append(PathFile)
FullModuleSubrout = macroSettings[1] + '!' + macroSettings[2] + '.' + macroSettings[3]
FullMacroLink.append(FullModuleSubrout)
if isWorkbookOpen(macroSettings[0], macroSettings[1]) == False:
# If the workbook is not open, Open workbook first.
system(f'start excel.exe "{PathFile}"')
# Give some time to start up Excel
sleep(2)
xlRunMacro(FullMacroLink)
def main():
macroSettings = []
# The settings below will execute the macro example
xlPath = r'C:\test\\' # Change add your needs
macroSettings.append(xlPath)
workbookName = 'Example.xlsm' # Change add your needs
macroSettings.append(workbookName)
xlModule = "Updates" # Change add your needs
macroSettings.append(xlModule)
xlSubroutine = "UpdateCurrentTime" # Change add your needs
macroSettings.append(xlSubroutine)
mainProgam(macroSettings)
if __name__ == "__main__":
main()
exit()
VBA Excel Macro
Option Explicit
Sub UpdateCurrentTime()
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("Current-Time")
With sht
sht.Cells(2, 1).Value = Format(Now(), "hh:mm:ss")
End With
End Sub
You can use it also as a dynamic module too. Save the module above as RunExcelMacro.py in Your python project. After just use the following lines:
from RunExcelMacro import mainProgam
mainProgram(macroSettings)
It will do the job, succes ...
You need to reference the module name as well
Example here my vba code under Module1
Option Explicit
Public Sub Example()
MsgBox "Hello 0m3r"
End Sub
and here is my python
from win32com.client import Dispatch
def run_excel_macro():
try:
excel = Dispatch("Excel.Application")
excel.Visible = True
workbook = excel.Workbooks.Open(
r"D:\Documents\Book1.xlsm")
workbook.Application.Run("Module1.Example")
workbook.SaveAs(r"D:\Documents\Book5.xlsm")
excel.Quit()
except IOError:
print("Error")
if __name__ == "__main__":
run_excel_macro()

Print Excel to pdf with xlwings

I am trying to print Excel files to pdf with xlwings. I am using the excel api for this.
I have tried it in two ways:
1/ Using the PrintOut() call with PrintToFile argument:
wb.api.PrintOut(PrintToFile=True, PrToFileName="5.pdf", Preview=True)
The problem here is Excel just prints the file, ignoring my additional settings.
2/ Using ExportAsFixedFormat
wb.api.ExportAsFixedFormat(0, str(SwmId) + ".pdf")
Here Excel flashes a bit, but does not do anything in the end.
For the record: I can't use a macro and call it from Python because I have about a thousand of these Excel files. So, I can't put the macro in every single one of them. It would probably be a workaround to create a custom function in VBA and than call it every file. But, honestly, it would be easier if I could just do this directly from Python, in one line of code.
Below is a self-standing code example of what worked on my machine to print an excel workbook to pdf (using the ExportAsFixedFormat method):
# Environment
# -----------
# OS: Windows 10
# Excel: 2013
# python: 3.7.4
# xlwings: 0.15.8
import os
import xlwings as xw
# Initialize new excel workbook
book = xw.Book()
sheet = book.sheets[0]
sheet.range("A1").value = "dolphins"
# Construct path for pdf file
current_work_dir = os.getcwd()
pdf_path = os.path.join(current_work_dir, "workbook_printout.pdf")
# Save excel workbook to pdf file
print(f"Saving workbook as '{pdf_path}' ...")
book.api.ExportAsFixedFormat(0, pdf_path)
# Open the created pdf file
print(f"Opening pdf file with default application ...")
os.startfile(pdf_path)
xlwings documentation recommends using xw.App():
from pathlib import Path
import xlwings as xw
import os
with xw.App() as app:
# user will not even see the excel opening up
app.visible = False
book = app.books.open(path_to_excelfile)
sheet = book.sheets[0]
sheet.page_setup.print_area = '$A$1:$Q$66'
sheet.range("A1").value = "experimental"
# Construct path for pdf file
current_work_dir = os.getcwd()
pdf_file_name = "pdf_workbook_printout.pdf"
pdf_path = Path(current_work_dir, pdf_file_name)
# Save excel workbook as pdf and showing it
sheet.to_pdf(path=pdf_path, show=True)

How to open multiple excel files with win32com?

Is there a way to simplify this with same kind with os.walk or glob?
from win32com.client import Dispatch
inputwb1 = "D:/apera/Workspace/Sounding/sounding001.xlsx"
inputwb2 = "D:/apera/Workspace/Sounding/sounding002.xlsx"
Sheet = 'OUTPUT'
excel = Dispatch("Excel.Application")
source = excel.Workbooks.Open(inputwb1)
source.Worksheets(Sheet).Range('F1:H500').Copy()
source.Worksheets(Sheet).Range('I1:K500').PasteSpecial(Paste=-4163)
source = excel.Workbooks.Open(inputwb2)
source.Worksheets(Sheet).Range('F1:H500').Copy()
source.Worksheets(Sheet).Range('I1:K500').PasteSpecial(Paste=-4163)
because this thing will take so much space if I want to write hundreds of it.
You seem to have almost answered your own question. Something like this might do it:
import glob
from win32com.client import Dispatch
Sheet = 'OUTPUT'
excel = Dispatch("Excel.Application")
for filename in glob.glob("D:/apera/Workspace/Sounding/sounding*.xlsx"):
source = excel.Workbooks.Open(filename)
source.Worksheets(Sheet).Range('F1:H500').Copy()
source.Worksheets(Sheet).Range('I1:K500').PasteSpecial(Paste=-4163)
you can open multiple excel files like this (example) :
import win32com.client
import os
path = ('D:\\New Folder\\MyExcelFiles\\')
fileslist = os.listdir('D:\\New Folder\\MyExcelFiles\\')
xl = win32com.client.DispatchEx('Excel.Application')
xl.Visible = True
for i in fileslist :
xl.Workbooks.Open(path+i)
if xl.Cells.Find('2014'):
xl.Cells.Replace('2015')
xl.Save()
xl.Workbooks.Close()
else:
xl.Workbooks.Close()

Python Win32 and excel

I am using WIN32com to use excel. I need to make sure that excel opens up new instances everytime. So if I run this and already have excel open I need it to open a new excel, and with in the script I need it to open a 2nd excel window for file 2 . This is what I am using: I can get it to open but not in new instances.
import win32com.client
import os
x1 = win32com.client.Dispatch("Excel.Application")
wb1= x1.workbooks.Open("X:\File1.xlsx")
wb2 = x1.workbooks.Open("X:\File2.xlsm")
x1.close("X:\File1.xlsx")
You can use DispatchEx to create a new instance of the application.
x1 = win32com.client.DispatchEx("Excel.Application")
x2 = win32com.client.DispatchEx("Excel.Application")
wb1 = x1.Workbooks.Open(.....
wb2 = x2.Workbooks.Open(.....
Roger

Categories

Resources