Saving an already open Excel window with python - python

I have been having issues finding an answer for this one. I am currently utilizing win32com, but while it is very powerful, I cannot figure out how to tap into an Excel file that's already open.
There is no alternative ; an external script opens Excel and writes to it the data, it is not located on the hard disk

You can access all the opened workbooks by looping through Excel.Application.Workbooks:
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
print("Active WB:", excel.ActiveWorkbook.Name)
for wb in excel.Workbooks:
print("WB:",wb.Name)
wb.Save()

I haven't got enough reputation to upvote Maxime Biette's answer but it's the right one.
If you just want one specific sheet to be saved:
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
print("Active WB:", excel.ActiveWorkbook.Name)
for wb in excel.Workbooks:
if wb.Name == 'thenameofyourfile.xlsx' :
print("WB:",wb.Name)
wb.Save()

Related

Python stream data into an opened excel file

I'm trying stream data from Python to an opened excel file. I've been using openpyxl to do this. Here's the code that I've so far,
from openpyxl import load_workbook
wb = load_workbook('some_data.xlsx')
ws = wb['MySheet']
while True:
current_val = some_method_that_gives_data()
ws['A1'].value = current_val
wb.save('some_data.xlsx')
The functionality I'm trying to achieve is to be able to update the excel data in realtime from Python. The problem is updating data this way gives permission error if the file is already open in MS-Excel (but I want to be able to update it while being open in other apps).
I guess this has more to do with file handling at the OS level, but I'm not able to figure out the solution for this issue.

Openpyxl Reading Non-empty Cells as None [duplicate]

I have a simple excel file:
A1 = 200
A2 = 300
A3 = =SUM(A1:A2)
this file works in excel and shows proper value for SUM, but while using openpyxl module for python I cannot get value in data_only=True mode
Python code from shell:
wb = openpyxl.load_workbook('writeFormula.xlsx', data_only = True)
sheet = wb.active
sheet['A3']
<Cell Sheet.A3> # python response
print(sheet['A3'].value)
None # python response
while:
wb2 = openpyxl.load_workbook('writeFormula.xlsx')
sheet2 = wb2.active
sheet2['A3'].value
'=SUM(A1:A2)' # python response
Any suggestions what am I doing wrong?
It depends upon the provenance of the file. data_only=True depends upon the value of the formula being cached by an application like Excel. If, however, the file was created by openpyxl or a similar library, then it's probable that the formula was never evaluated and, thus, no cached value is available and openpyxl will report None as the value.
I have replicated the issue with Openpyxl and Python.
I am currently using openpyxl version 2.6.3 and Python 3.7.4. Also I am assuming that you are trying to complete an exercise from ATBSWP by Al Sweigart.
I tried and tested Charlie Clark's answer, considering that Excel may indeed cache values. I opened the spreadsheet in Excel, copied and pasted the formula into the same exact cell, and finally saved the workbook. Upon reopening the workbook in Python with Openpyxl with the data_only=True option, and reading the value of this cell, I saw the proper value, 500, instead of the wrong value, the None type.
I hope this helps.
I had the same issue. This may not be the most elegant solution, but this is what worked for me:
import xlwings
from openpyxl import load_workbook
excel_app = xlwings.App(visible=False)
excel_book = excel_app.books.open('writeFormula.xlsx')
excel_book.save()
excel_book.close()
excel_app.quit()
workbook = load_workbook(filename='writeFormula.xlsx', data_only=True)
I have suggestion to this problem. Convert xlsx file to csv :).
You will still have the original xlsx file. The conversion is done by libreoffice (it is that subprocess.call() line).You can use also Pandas for this as a more pythonic way.
from subprocess import call
from openpyxl import load_workbook
from csv import reader
filename="test"
wb = load_workbook(filename+".xlsx")
spread_range = wb['Sheet1']
#what ever function there is in A1 cell to be evaluated
print(spread_range.cell(row=1,column=1).value)
wb.close()
#this line can be done with subprocess or os.system()
#libreoffice --headless --convert-to csv $filename --outdir $outdir
call("libreoffice --headless --convert-to csv "+filename+".xlsx", shell=True)
with open(filename+".csv", newline='') as f:
reader = reader(f)
data = list(reader)
print(data[0][0])
or
# importing pandas as pd
import pandas as pd
# read an excel file and convert
# into a dataframe object
df = pd.DataFrame(pd.read_excel("Test.xlsx"))
# show the dataframe
df
I hope this helps somebody :-)
Yes, #Beno is right. If you want to edit the file without touching it, you can make a little "robot" that edits your excel file.
WARNING: This is a recursive way to edit the excel file. These libraries are depend on your machine, make sure you set time.sleep properly before continuing the rest of the code.
For instance, I use time.sleep, subprocess.Popen, and pywinauto.keyboard.send_keys, just add random character to any cell that you set, then save it. Then the data_only=True is working perfectly.
for more info about pywinauto.keyboard: pywinauto.keyboard
# import these stuff
import subprocess
from pywinauto.keyboard import send_keys
import time
import pygetwindow as gw
import pywinauto
excel_path = r"C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE"
excel_file_path = r"D:\test.xlsx"
def focus_to_window(window_title=None): # function to focus to window. https://stackoverflow.com/a/65623513/8903813
window = gw.getWindowsWithTitle(window_title)[0]
if not window.isActive:
pywinauto.application.Application().connect(handle=window._hWnd).top_window().set_focus()
subprocess.Popen([excel_path, excel_file_path])
time.sleep(1.5) # wait excel to open. Depends on your machine, set it propoerly
focus_to_window("Excel") # focus to that opened file
send_keys('%{F3}') # excel's name box | ALT+F3
send_keys('AA1{ENTER}') # whatever cell do you want to insert somthing | Type 'AA1' then press Enter
send_keys('Stackoverflow.com') # put whatever you want | Type 'Stackoverflow.com'
send_keys('^s') # save | CTRL+S
send_keys('%{F4}') # exit | ALT+F4
print("Done")
Sorry for my bad english.
As others already mentioned, Openpyxl only reads cashed formula value in data_only mode. I have used PyWin32 to open and save each XLSX file before it's processed by Openpyxl to read the formulas result value. This works for me well, as I don't process large files. This solution will work only if you have MS Excel installed on your PC.
import os
import win32com.client
from openpyxl import load_workbook
# Opening and saving XLSX file, so results for each stored formula can be evaluated and cashed so OpenPyXL can read them.
excel_file = os.path.join(path, file)
excel = win32com.client.gencache.EnsureDispatch('Excel.Application')
excel.DisplayAlerts = False # disabling prompts to overwrite existing file
excel.Workbooks.Open(excel_file )
excel.ActiveWorkbook.SaveAs(excel_file, FileFormat=51, ConflictResolution=2)
excel.DisplayAlerts = True # enabling prompts
excel.ActiveWorkbook.Close()
wb = load_workbook(excel_file)
# read your formula values with openpyxl and do other stuff here
I ran into the same issue. After reading through this thread I managed to fix it by simply opening the excel file, making a change then saving the file again. What a weird issue.

Trouble with Excel Autofit in Python (3.6)

I am trying to autofit the columns in my python generated xlsx file.
Found the code from here[https://stackoverflow.com/a/33665967/5518944], but getting an exception.
I am using Microsoft Office 2015.
Using this code:
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
ends up in following error:
[...]Python36\lib\site-packages\win32com\client\gencache.py", line 236, in GetModuleForCLSID
__import__(sub_mod_name)
ModuleNotFoundError: No module named 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x8._Application'
Are you able to help me with this problem?
I can access and edit .xlsx files using:
from win32com.client import Dispatch
xl = Dispatch("Excel.Application")
wb = xl.Workbooks.Open(Filename="yourfile.xlsx")
ws = wb.Worksheets(1)
etc..
But i'm not sure if you really need EnsureDispatch, see this for mor about the differences.

Python to close a workbook using win32com

I'm using python 2.7.11 on a windows 10 machine where I'm updating a file using VBA contained in the Update_table.xls worksheet. I'm using the below code but I am finding that the Excel worksheet sometimes remains open in the task manager once the py script has ran.
import win32com.client
xl=win32com.client.Dispatch("Excel.Application")
xl.Workbooks.Open(Filename="C:\Projects\Update_table.xlsb",ReadOnly=1)
xl.Application.Run("Update2")
xl = 0
As I am running multiple scripts at once is there a way to ensure the workbook is closed? & not close the whole excel application.
Not sure what you mean by running multiple scripts at once, but to close the workbook:
wb = xl.Workbooks.Open(Filename="C:\Projects\Update_table.xlsb",ReadOnly=1)
...
wb.Close()
wb = None

editing existing excel workbook using xlrd, xlwt and xlutils

How to edit and save the data in an existing excel workbook using xlrd, xlwt and xlutils module?
could someone please provide a sample code to edit and save the data in excel workbook?
I am trying to put data from one workbook to another.
import xlrd, xlwt, xlutils
wb1 = xlrd.open_workbook('workbook1.xls', formatting_info=True)
wb2 = xlrd.open_workbook('workbook2.xls', formatting_info=True)
value 1 == wb2.sheet_by_name('Sheet1).cell(2,1).value
wb1.sheet_by_name('Sheet1').cell(2,2).value == value1
How to save this data in workbook1.xls?
Sorry, I asked this before, but I am trying to be more clear about my question this time.
Thank you very much.
You can save with wb1.save('workbook1.xls'). You might get an IOError that the file already exists. In that case try to os.remove() the file before saving.
I agree with the previous answer of using the xlwt library save method. But you should also do some proof reading of your code. You are missing a closing quote for Sheet1 and variable names cannot have spaces.

Categories