xlwings doesn't write data in file.xlsm when running through excel - python

I am trying to use xlwings for simple consolidation from several xls files.
For this, I have a all_files.xlsm file that contains a button with macros assigned to it. The macros looks like:
Sub check_data()
RunPython ("import python_code; python_code.consolidation()")
End Sub
In same folder I have a file python_code.py with function "consolidation" inside.
I also use Workbook.set_mock_caller() in order to have an opportunity to run a code through python interface. It looks like:
def consolidation(file_path):
*** smth to get the data I need ***
...
*** after I got data ***
Range('A1').table.clear_contents() #string1
Range('A1').value = data #string2
def main():
consolidation(file_path)
if __name__ == '__main__':
xl.Workbook.set_mock_caller(path_to_file)
main()
The problem is that when I am running the script through the button in excel file last two strings (string1 and string2) - Range('A1').table.clear_contents() and Range('A1').value = data doesn't work. Although the rest of the code works fine (however, it contains xlwing also). Moreover, if I run the script through the python interface using set mock caller, it works just fine, including string1 and string2 (marked in the code).
Any help and advices are really appreciated!

I found decision for my problem. For using xlwings in python you should import xlwings.bas in your excel file (see manual for xlwings). It turns out, that I imported it for this macros before I've updated xlwings. So I deleted this file and imported a new one. Everything works fine now.

Related

How to refresh all pivot table of an excel file using Python xlwings [duplicate]

I am trying to refresh a pivot table in excel upon data written by XLWINGS.
As I don't know how to do it directly from XLWINGS, I tried to use VBA.
Let's split my process in 2 steps:
Step1
I launch the python code from vba (my module name is "PosRep", the python code writtes back a range of data in a specified sheet thanks to xlwings.
Sub launchPython()
RunPython ("import PosRep; PosRep")
End Sub
Step 2
But as I don't know in advance the size of my newly created Range in Excel, I want to select it, add a new Name (NamedRange) and refresh my pivot (already linked to the NamedRange).
Sub SelectRange()
Worksheets("GPODump").Range("A1").Select
'...
End Sub
Both Subs work independently well. But I cannot manage to make them work in a raw. The following code:
Sub Main()
launchPython
SelectRange
End Sub
produces a VBA error "Select method of Range class failed" on the statement:
Worksheets("GPODump").Range("A1").Select
I presume there is a conflict with the XLWINGS VBA module but I can't figure out what it can be...
Anyone's help would be more than welcome !
Thx
The problem came from the VBA code. The following code works fine:
Sheets("GPODump").Select
Sheets("GPODump").Range("A1").Select
Maybe it's too late but you can do it within xlwings - this is what worked for me:
import xlwings as xw
# open excel App
app_excel = xw.App(visible = False)
# open the excel file, select the tab and the PivotTable to refresh
wbook = xw.Book( 'YourFile.xlsx' )
wbook.sheets['Tab1'].select()
wbook.api.ActiveSheet.PivotTables('PivotTableName').PivotCache().refresh()
I was looking how to solve this for Mac, here is how I did to refresh all pivot tables and etc:
wb.api.active_sheet.refresh_all(wb.api)
Hopes that this saves someone else time. Took me a while to figure it out.

Start python script from excel with input

I have a Python script (gui.py - a calculation program, written by somebody else). I try to run this from excel with input data from the same excel file. It works fine when I start the script as:
objShell.Run PythonExe & PythonScript3
In the python script I used the following to get f.ex data from H5 cell, works also fine:
import openpyxl
wb = openpyxl.load_workbook("01.xlsm")
ws = wb.active
mastNumber = ws['H5']
But I don't want to edit a lot in gui.py (have just simple changes) so I planned to use a 2nd script (caller.py) which gets the data from Excel, then I import this to gui.py and there I just use the variable from caller.py. It works also as long as I start gui.py directly. When I start it from Excel I get an error msg.
error msg
So as long as the flow is not Excel -> gui-py -> which imports caller to get data from same Excel file -everything works fine.
I am open to any solution for this problem or a completely new approach if there is better for somebody with limited programming skills.
Looking at the error, can you try putting complete path of the excel file at line wb = openpyxl.load_workbook("01.xlsm") instead of just 01.xlsm.

VBScript kills program before text file is made

I made a vbscript to open an excel doc, then runs a python program that pulls data from the documents tables and prints it to a text file. The script is supposed to wait until the python program is done creating the text doc then close the excel doc, but for whatever reason my python program closes before it even has a chance to make that text doc.
I even changed the python code to just print a simple 'Hello World' into a new text document in case pulling data from excel was causing problems but the text document still wasn't created.
This is the script that i'm running:
Set xl = CreateObject("Excel.application")
xl.Application.Workbooks.Open "C:\Users\V\Documents\_PROGRAMS_\TEST.xlsx"
xl.Application.Visible = True
Dim oshell
Set oshell = WScript.CreateObject("WScript.Shell")
oshell.CurrentDirectory = "C:\Users\V\Documents\_PROGRAMS_\"
windowStyle = 1
waitUntilFinished = True
oshell.run "python table.py", windowStyle, waitUntilFinished
xl.Application.Quit
I don't think adding the python program is important since that isn't really the problem. Although I will say that I tried putting a delay in the python program to see if that would change anything (it didn't).
I though adding the two extra arguments to .run would make it wait until the process is finished but I guess I must be missing something?
I'm just starting to learn how to use vbscript so any explanations of code would be welcomed!
Thanks!
EDIT: So after more testing it seems that it does have something to do with accessing the excel document, as just printing 'Hello World' to a file did actually work and the file was created (I made it in the wrong directory by accident so I was looking in the wrong place). But trying it with the data from the excel document no file is created, the program just ends
So here's the python code I wrote:
#!/usr/bin/python27
import pandas as pd
table = pd.read_excel("TEST.xlsx") #Get excel doc
file = open("text.txt", "w") #Open new file
file.write(table.columns.values) #Print out column headers
file.write("Hello!")
file.close()

Refresh Pivot Table with XLWINGS

I am trying to refresh a pivot table in excel upon data written by XLWINGS.
As I don't know how to do it directly from XLWINGS, I tried to use VBA.
Let's split my process in 2 steps:
Step1
I launch the python code from vba (my module name is "PosRep", the python code writtes back a range of data in a specified sheet thanks to xlwings.
Sub launchPython()
RunPython ("import PosRep; PosRep")
End Sub
Step 2
But as I don't know in advance the size of my newly created Range in Excel, I want to select it, add a new Name (NamedRange) and refresh my pivot (already linked to the NamedRange).
Sub SelectRange()
Worksheets("GPODump").Range("A1").Select
'...
End Sub
Both Subs work independently well. But I cannot manage to make them work in a raw. The following code:
Sub Main()
launchPython
SelectRange
End Sub
produces a VBA error "Select method of Range class failed" on the statement:
Worksheets("GPODump").Range("A1").Select
I presume there is a conflict with the XLWINGS VBA module but I can't figure out what it can be...
Anyone's help would be more than welcome !
Thx
The problem came from the VBA code. The following code works fine:
Sheets("GPODump").Select
Sheets("GPODump").Range("A1").Select
Maybe it's too late but you can do it within xlwings - this is what worked for me:
import xlwings as xw
# open excel App
app_excel = xw.App(visible = False)
# open the excel file, select the tab and the PivotTable to refresh
wbook = xw.Book( 'YourFile.xlsx' )
wbook.sheets['Tab1'].select()
wbook.api.ActiveSheet.PivotTables('PivotTableName').PivotCache().refresh()
I was looking how to solve this for Mac, here is how I did to refresh all pivot tables and etc:
wb.api.active_sheet.refresh_all(wb.api)
Hopes that this saves someone else time. Took me a while to figure it out.

Using Python to read VBA from an Excel spreadsheet

I would like to write a VBA diff program in (preferably) Python. Is there a Python library that will allow me to read the VBA contained in an Excel spreadsheet?
Here's some quick and dirty boilerplate to get you started. It uses the Excel COM object (a Windows only solution):
from win32com.client import Dispatch
wbpath = 'C:\\example.xlsm'
xl = Dispatch("Excel.Application")
xl.Visible = 1
wb = xl.Workbooks.Open(wbpath)
vbcode = wb.VBProject.VBComponents(1).CodeModule
print vbcode.Lines(1, vbcode.CountOfLines)
This prints the silly macro I recorded for this example:
Sub silly_macro()
'
' silly_macro Macro
'
'
Range("B2").Select
End Sub
Note that Lines and VBComponents use 1-based indexing. VBComponents also supports indexing by module name. Also note that Excel requires backslashes in paths.
To dive deeper see Pearson's Programming The VBA Editor. (The above example was cobbled together from what I skimmed from there.)
I have created an application that does this called VbaDiff. If you provide it two Excel files it will compare the VBA code in each. You can also run it from the command line, or use the version that comes with an API if you want to integrate it with your own programs.
You can find out more at http://www.technicana.com/vbadiff-information.html
Chris

Categories

Resources