Using python to call a excel macro - python

I'm trying to write a python code that will run a macro in a excel workbook. I know the file name and name of the vba macro. I don't need to read any information into the python file I simple need to perform this function.
I ultimately want to run this python code periodically and I want it to call the same VBA function multiple times in a day.
import openpyxl
excel_document = openpyxl.load_workbook('python test.xlsm')
print type(excel_document)

I found this Code on Stackoverflow. Maybe it helps you.
Resource:
Running an Excel macro via Python?
import win32com.client
if os.path.exists("excelsheet.xlsm"):
xl = win32com.client.Dispatch("Excel.Application")
wb = xl.Workbooks.Open(os.path.abspath("C:\Users\{Username}\Desktop\test.xlsm"), ReadOnly=0)
wb.Sheets('Sheet1').Select()
xl.Application.Run("test.xlsm!Module1.macroname")
## xl.Application.Save() # if you want to save then uncomment this line and change delete the ", ReadOnly=1" part from the open function.
xl.Application.Quit() # Comment this out if your excel script closes
del xl```

Related

Question about error when saving xlsm file using xlwings

I want to open an xlsm file via xlwings and then edit it and save it. However, some problems arose.
If I run the code with no excel file working, or just open another excel file and do not edit the excel file, it works fine. However, if I open an Excel file and do some work, for example open a blank Excel file and enter 'test' in cell A1, and run the code, sometimes it works, but sometimes it becomes unresponsive in the third line.(wb_xl = xw.Book(copy)) In this case, the code does not jump from the third line in an unresponsive state. What makes more sense is that the code works fine in some cases.
I want to know when the code works fine in all cases.
And there is one more problem.
If this code is executed while working with another Excel, only wb_xl should be terminated. I don't want another Excel to be closed. I want to exit only wb_xl. However, when the app.quit() code is executed, all open Excels are closed. In this case, how can I close only the Excel(wb_xl) opened through the code without closing the working Excel?
import xlwings as xw
copy = 'C:/Users/ijung/Desktop/210919_Mk_Lot_test/210922_101test.xlsm'
wb_xl = xw.Book(copy) #sometimes no response in this line
ws_xl = wb_xl.sheets['Main']
app = xw.apps.active
ws_xl.range('A1').value = 'test'
wb_xl.save()
app.quit()
#wb_xl.app.kill()
#wb_xl.close()
I also used openpyxl. However, in this part of wb_open.save(copy), an error such as xml.etree.ElementTree.ParseError: mismatched tag: line 20, column 8 occurred. When I use xlsx, the save works fine, but when I use xlsm, an error occurs.
import openpyxl
wb_open = openpyxl.load_workbook(copy, read_only = False, keep_vba = True)
ws_open = wb_open.active
ws_open.cell(1,1).value = 'test'
wb_open.save(copy) #error
wb_open.close()
As a result, the purpose of this code is to open the xlsm file by executing this code even when working with another Excel, edit and save, and close only this xlsm file.However, using multiple packages and searching multiple sites could not solve the problem.I'm under a lot of stress with this issue. Any help would be greatly appreciated. Please help me.
Thanks in advance.
openpyxl does not works with xlsm files that contains form objects
I think the problem is in app.quit() you are closing the excel instance, just use wb_xl.close()
import xlwings as xw
copy = 'C:/Users/ijung/Desktop/210919_Mk_Lot_test/210922_101test.xlsm'
wb_xl = xw.Book(copy) #sometimes no response in this line
ws_xl = wb_xl.sheets['Main']
#app = xw.apps.active # don't needed
ws_xl.range('A1').value = 'test'
wb_xl.save()
wb_xl.close()
This should only close the book, take a look this post has insteresting answers

Run Excel macro from different Excel file

I know there already are many questions regarding this topic, but I couldn't figure out a solution that works out for me.
I want to run an Excel macro stored in an 'xlsm' file, but I need to run it on a different Excel file ('xlsx').
Whenever I try the code below, I get an error message saying that the macro wasn't found, so I suppose the problem has to do with the pathing.
This is what I have:
import win32com.client
import os
try:
excel = win32com.client.Dispatch('Excel.Application')
excel_path = r'C:\Users\martin\Desktop\testing_excel.xlsx'
workbook = excel.Workbooks.Open(excel_path, ReadOnly=1)
excel.Application.Run("'macro_testing.xlsm'!local_macro")
workbook.Save()
excel.Quit()
print('Macro run succesfully')
except Exception as e:
print(e)
excel.Quit()
The 'xlsm' file with the macro is named 'macro_testing.xlsm', and the macro name is 'local_macro'.
Thanks in advance!
When I have to do similar, I store the macro in a command book (.xlsm) - or even .xlam that is called from the command book (which is .xlsm) and it then opens, manipulates, saves and closes .xlsx as appropriate.
If you try to run it from within an .xlsx, you'll never be able to save the code that has done the run, not exactly advisable for repetitive workflows.
So,
macro_testing.xlsm could have another sub which would be something like:
sub runExternal()
with Sheets("Sheet1").
extPath = cells(1,2)
extBook = cells(2,2)
'Declaring the path & workbook to use within the master workbook's "Sheet1"
workbooks.open(extPath & extBook) ReadOnly:False
call local_macro()
application.displayalerts = false 'Just in case there are any GUI prompts
workbooks(extBook).close saveChanges:=True
application.displayalerts = true
end sub
For anybody there who was experiencing the same problem I had, what I finally did was open the two Excel files, like this:
import os
excel_path = os.path.abspath('Excel_to_run_macro.xlsx')
if os.path.exists(excel_path):
xl = win32com.client.Dispatch('Excel.Application')
xl.Workbooks.Open(os.path.abspath('Excel_with_macro.xlsm'), ReadOnly=1)
workbook = xl.Workbooks.Open(excel_path, ReadOnly=1)
xl.Application.Run("'Excel_with_macro.xlsm'!Macro_name")
workbook.Save()
xl.Application.Quit()
del xl

Creating Excel macros from python

I would like to create a Excel VBA macro from python.
I already managed to add a module sheet via win32com, but I dont know how to write the code into the module. Here is the code I am using:
import win32com.client
xl = win32com.client.dynamic.Dispatch("Excel.Application")
xl.Visible=True
out_file = "workbook.xlsm"
xl.Workbooks.Open(out_file)
Book=xl.Application.Workbooks(1)
newModule=Book.Modules.Add()
Now: How do I write a string containing the macro into the new module sheet?

How can I check if a specific workbook (Excel file) is opened? After I find out, how can I close it?

I created a Python script which scrapes a website, grabs the information I need and writes it in an Excel file. The problem is that, sometimes, after I check what has been written, I forget to close the Excel file and the script no longer runs (due to the fact that the file is already opened)
To open/write/save/close the Excel file, I am using the openpyxl library, but I don't know how to check if that specific file is opened and how to close it afterwards.
#writing to excel
pathexcel = r'C:\Users\...\Data.xlsx'
wb = load_workbook(pathexcel)
sheet = wb.active
sheet.append(row1)
sheet.append(row2)
sheet.append(row3)
wb.save(pathexcel)
Thank you!

Why does Excel macro work in Excel but not when called from Python?

I have an Excel macro that deletes a sheet, copies another sheet and renames it to the same name of the deleted sheet. This works fine when run from Excel, but when I run it by calling the macro from Python I get the following error message:
Run-time error '1004' - Cannot rename a sheet to the same name as
another sheet, a referenced object library or a workbook referenced by
VisualBasic.
The macro has code like the following:
Sheets("CC").Delete
ActiveWindow.View = xlPageBreakPreview
Sheets("FY").Copy After:=Sheets(Sheets.Count)
Sheets(Sheets.Count).Name = "CC"
and the debugger highlights the error on the last line where the sheet is renamed. I've also tried putting these calls directly in python but get the same error message.
Any suggestions are much appreciated!
Thanks.
I ran the code inside Excel VBA.
I am guessing that the following line is failing.
Sheets("CC").Delete
And that is the reason, you can't give the new sheet same name as existing (non-deleted) sheet.
Put Application.DisplayAlerts = False before Sheets("CC").Delete and Application.DisplayAlerts = True once you are finished with the code.
I haven't used python but it seems the library is swallowing that error for you and letting you go ahead to the next statement.
Hope that helps.
Behind the scenes, VB and VBA are maintaining references to COM objects for the application, worksheets etc. This is why you have the globals 'Application', 'Worksheets' etc. It is possible that VBA is still holding a reference to the worksheet, so Excel hasn't tidied it up properly.
Try not using these implicit globals and referencing the items in the object model explicitly. Alternatively you could do it directly in Python.
Here's a python script that will do something like what you want:
import win32com.client
xl = win32com.client.Dispatch ('Excel.Application')
xl.Visible = True
wb = xl.Workbooks.Add()
wb.Worksheets[0].Delete()
wb.Worksheets.Add()
wb.Worksheets[0].Name = 'Sheet1'

Categories