I am a beginner in python. I have written few DBQ statements in excel to fetch
result in excel which should be refreshed whenever the excel is opened. Have given the correct setting in connection properties.
Below is my python code for refreshall:-
import win32com.client
import time
xl = win32com.client.DispatchEx("Excel.Application")
wb = xl.workbooks.open("D:\\Excel sheets\\Test_consolidation.xlsx")
xl.Visible = True
time.sleep(10)
wb.Refreshall()
I have 3 sheets in the excel file, which has 3 different connections. I want to refresh one after the other.
Can someone help me with the python code to refresh the connections individually ? I would be really grateful for your help.
So if you want to refresh all of them but one after the other, instead of wb.Refreshall(), the command would be:
for conn in wb.connections:
conn.Refresh()
If you want to link (in a dictionary for example) a connection to a sheet:
dict_conn_sheet = {} # create a new dict
for conn in wb.connections: # iterate over each connection in your excel file
name_conn = conn.Name # get the name of the connection
sheet_conn = conn.Ranges(1).Parent.Name # get the name of the sheet linked to this connection
# add a key (the name of the sheet) and the value (the name of the connection) into the dictionary
dict_conn_sheet[sheet_conn] = name_conn
Note: if one sheet has more than one connection, this is not a good way.
Then, if you want to update only one connection on a specific sheet (in my example it is called Sheet1):
sheet_name = 'Sheet1'
# refresh the connection linked to the sheet_name
# if existing in the dictionnary dict_conn_sheet
wb.connections(dict_conn_sheet[sheet_name]).Refresh()
Finally, if you know directly the name of the connection you want to update (let's say connection_Raj), just enter:
name_conn = 'connection_Raj'
wb.connections(name_conn).Refresh()
I hope it's clear even if it does not answer exactly to your question as I'm not sure I understood what you want to do.
Related
I looked around a bit but could not find an answer. I found RefreshAll() which is not what I want to do.
Say I have a workbook named "DATA" with following sheets, "Forecast Temps", "Actual Temps", "Table", "Summary".
Now imagine that Forecast Temps sheet has a time series function that grabs data from NWS. This worksheet needs to be refreshed and then temps added into specified column in worksheet "Table". After this, Sheet Summary can be refreshed to determine new high and lows for that day.
Yes - I could run RefreshAll() at each step, but this seems redundant and would take the script longer to run. I was wondering if there was a way to refresh a single sheet w/ xlwings.
I also know you can do it in VBA, but my plan is to write a python script and then create a Sub where I call RunPython ("ScriptName").
Would I be able to do something like:
import xlwings as xw
wb = xw.Book("path")
forecast_temps = wb.sheet[0]
summary = wb.sheet[1]
forecast_temps.refresh() #do not know the correct func here (if there is one)?
I think RefreshAll() is not part of xlwings API. You may call the Excel API like this: wb.api.RefreshAll().
If you know how to do it in VBA, the same will probably work in xlwings using .api. I think you will have some kind of workbook connection. wb.api.Connections should return a list of all workbook connections. From there you can go on with the WorkbookConnection-Objects, which have a Refresh() method.
Background:
I am fetching Option chain for a symbol from web and then writing it to an excel sheet. I also have another excel sheet in the same workbook from which I take inputs for the program to run. All of this I am doing with excel 2016.
Sample of the code from program as the whole program is pretty long:
import xlwings as xw
excel_file = 'test.xlsx'
wb = xw.Book(excel_file)
wb.save()
# Fetching User input for Script/Ticker else it will be set to NIFTY as default
try:
Script_Input = pd.read_excel(excel_file, sheet_name = 'Input_Options', usecols = 'C')
script = Script_Input.iloc[0,0]
except:
script = 'NIFTY'
# Writing data in the sheet
sht_name = script + '_OC'
try:
wb.sheets.add(sht_name)
print('new sheet added')
wb.save()
except:
pass
# print('sheet already present')
# directing pointer towards current sheet to be written
sheet = wb.sheets(sht_name)
sheet.range('A4').options(index = False, header = False).value = df
sheet.range('B1').value = underlying
sheet.range('C1').value = underlying_Value
# sheet.range('A3').options(index = False, header = False).value = ce_data_final
# sheet.range('J3').options(index = False, header = False).value = pe_data_final
wb.save()
Problem: Since yesterday, I am able to open my excel workbook with excel 2016 and change inputs for my program but, I do not get any data written in the sheet that takes output from the program. The program runs perfectly as I can test the output on terminal. Also, once I delete the sheet no new sheet is being created as it should.
What I tried: I have uninstalled every other version of excel I had, so now only excel 2016 is present.
I have made sure that all the respective file formats use excel 2016 as the default app.
Also note that, 2 days ago I was able to write data perfectly in the respective sheet but now I am not able to do so.
Any help appreciated...
Sorry to everyone who tried to solve this question.
after #buran asked about 'df' I looked into my code and found that I had a return statement before writing 'df' into sheet (I have created a separate function to write data in excel). Now that I have moved that statement to its proper place the code is working fine. I am extremely sorry as I did not realise what the problem was in the 1st place and assumed it had to do with excel and python. Now the program runs perfectly and I am getting the output I want.
I am trying to automate a macro-enabled Excel workbook process using Python. I would like to use win32com if possible but am open to switching to other libraries if needed.
Once I get the workbook open and on the sheet I need, there is data already there with auto-filters applied. I just need to filter on a column to make the data available to the macro when I run it.
I use wb.RefreshAll() to import the data from existing connections. Eventually I will need to pass a value entered by the user to the filter as it will be different each time the automation runs.
Most solutions involve copying select data to a Pandas DataFrame etc. but I need the filtered data to remain in the sheet so it can be used by the macro.
I recently wrote a Python script to automate Macros. Basically, the idea was to batch-edit a collection of .doc files and have a macro run for all of them, without having to open them one by one.
First:
What is this macro you want to run?
Second:
What is the data that you need to make visible, and what do you mean by that?
To get you started, try this:
data = [{"test1": 1, "test2": 2}, {"test1": 3, "test2": 4}]
import win32com.client as win32
def openExcel():
xl = win32.gencache.EnsureDispatch('Excel.Application')
wb = xl.Workbooks.Add()
#wb = xl.Workbooks.Open(filepath)
ws = wb.Sheets(1) #The worksheet you want to edit later
xl.Visible = True
return ws
def print2Excel(datapoint:dict, ws):
print(datapoint)
const = win32.constants #.Insert()-Methods keywargs are packaged into const.
ws.Range("A1:B1").Insert(const.xlShiftDown, const.xlFormatFromRightOrBelow)
ws.Cells(1,1).Value = datapoint["test1"]
ws.Cells(1,2).Value = datapoint["test2"]
ws = openExcel() #<- When using Open(filepath), pass the whole filepath, starting at C:\ or whatever drive.
for datapoint in data:
print2Excel(datapoint, ws)
This showcases some of the basics on how to work with Excel objects in win32com
Using pygsheets, I was looking around for a good way to open a Google sheet (by title) if it already exists, otherwise create it.
At the same time, I also wanted to make it r/w to myself and r/o to the rest of the world upon creating it.
Here's something that does just that:
import pygsheets
creds_file = "/path/to/your_creds_file.json"
gc = pygsheets.authorize(service_file=creds_file)
sheet_title = "my_google_sheet"
# Try to open the Google sheet based on its title and if it fails, create it
try:
sheet = gc.open(sheet_title)
print(f"Opened spreadsheet with id:{sheet.id} and url:{sheet.url}")
except pygsheets.SpreadsheetNotFound as error:
# Can't find it and so create it
res = gc.sheet.create(sheet_title)
sheet_id = res['spreadsheetId']
sheet = gc.open_by_key(sheet_id)
print(f"Created spreadsheet with id:{sheet.id} and url:{sheet.url}")
# Share with self to allow to write to it
sheet.share('YOUR_EMAIL#gmail.com', role='writer', type='user')
# Share to all for reading
sheet.share('', role='reader', type='anyone')
# Write something into it
wks = sheet.sheet1
wks.update_value('A1', "something")
I am using openpyxl to write to a workbook. But that workbook needs to be closed in order to edit it. Is there a way to write to an open Excel sheet? I want to have a button that runs a Python code using the commandline and fills in the cells.
The current process that I have built is using VBA to close the file and then Python writes it and opens it again. But that is inefficient. That is why I need a way to write to open files.
If you're a Windows user there is a very easy way to do this. If we use the Win32 Library we can leverage the built-in Excel Object VBA model.
Now, I am not sure exactly how your data looks or where you want it in the workbook but I'll just assume you want it on the sheet that appears when you open the workbook.
For example, let's imagine I have a Panda's DataFrame that I want to write to an open Excel Workbook. It would like the following:
import win32com.client
import pandas as pd
# Create an instance of the Excel Application & make it visible.
ExcelApp = win32com.client.GetActiveObject("Excel.Application")
ExcelApp.Visible = True
# Open the desired workbook
workbook = ExcelApp.Workbooks.Open(r"<FILE_PATH>")
# Take the data frame object and convert it to a recordset array
rec_array = data_frame.to_records()
# Convert the Recordset Array to a list. This is because Excel doesn't recognize
# Numpy datatypes.
rec_array = rec_array.tolist()
# It will look something like this now.
# [(1, 'Apple', Decimal('2'), 4.0), (2, 'Orange', Decimal('3'), 5.0), (3, 'Peach',
# Decimal('5'), 5.0), (4, 'Pear', Decimal('6'), 5.0)]
# set the value property equal to the record array.
ExcelApp.Range("F2:I5").Value = rec_array
Again, there are a lot of things we have to keep in mind as to where we want it pasted, how the data is formatted and a whole host of other issues. However, at the end of the day, it is possible to write to an open Excel file using Python if you're a Windows' user.
Generally, two different processes shouldn't not be writing to the same file because it will cause synchronization issues.
A better way would be to close the existing file in parent process (aka VBA code) and pass the location of the workbook to python script.
The python script will open it and write the contents in the cell and exit.
No this is not possible because Excel files do not support concurrent access.
I solved this doing the follow: Create an intermediary excel file to recieve data from python and then create a connexion between this file and the main file. The excel has a tool that allow automatically refresh imported data from another workbook. Look this LINK
wb = openpyxl.load_workbook(filename='meanwhile.xlsm', read_only=False, keep_vba=True)
...
wb.save('meanwhile.xlsm')
In sequence open your main excel file:
On the Data tab, create a connexion with the "meanwhile" workbook, then in the Connections group, click the arrow next to Refresh, and then click Connection Properties.
Click the Usage tab.
Select the Refresh every check box, and then enter the number of minutes between each refresh operation.
Using below code I have achieved, writing the Excel file using python while it is open in MS Execl.
This solution is for Windows OS, not sure for others.
from kiteconnect import KiteConnect
import xlwings as xw
wb = xw.Book('winwin_safe_trader_youtube_watchlist.xlsx')
sht = wb.sheets['Sheet1']
stocks_list = sht.range('A2').expand("down").value
watchlist = []
time.sleep(10)
for name in stocks_list:
symbol = "NSE:" + name
watchlist.append(symbol)
print(datetime.datetime.today().time())
data = kite.quote(watchlist)
df = pd.DataFrame(data).transpose()
df = df.drop(['depth', 'ohlc'], 1)
print(df)
sht.range('B1').value = df
time.sleep(1)
wb.save('winwin_safe_trader_youtube.xlsx')