with statement python __enter__ attribute error - python

This :
def add_to_excel(list_to_save, file_to_save_in):
my_file = dir_path + '\\' + file_to_save_in
with openpyxl.load_workbook(filename=my_file) as links_excel:
sheet = links_excel['Sheet1']
for i in list_to_save:
sheet.append(i)
links_excel.save(filename)
return
returns this:
3 my_file = dir_path + '\\' + file_to_save_in
----> 4 with openpyxl.load_workbook(filename=my_file) as links_excel:
5 sheet = links_excel['Sheet1']
6 for i in list_to_save:
AttributeError: __enter__
Tried this:
You're not using with statement and there's no close() statement so if this is not the first time you're running the code, it's likely that you haven't closed the file properly and it is still sitting in the memory and prevents access.
Edit:
Apparently closing the excel fixes it, and the with statement is not needed.
links_excel.close()
def add_to_excel(list_to_save, file_to_save_in):
my_file = os.path.join(dir_path, file_to_save_in)
links_excel=openpyxl.load_workbook(filename=my_file)
sheet = links_excel['Sheet1']
for i in list_to_save:
sheet.append(i)
links_excel.save(my_file)
links_excel.close()

from openpyxl documentation
Read an existing workbook:
from openpyxl import load_workbook
wb = load_workbook(filename = 'empty_book.xlsx')
sheet_ranges = wb['range names']
print(sheet_ranges['D18'].value)
This is an example on how to use the load_workbook method, so you don't need to use that with statement. Just use assignment.
def add_to_excel(list_to_save, file_to_save_in):
my_file = dir_path + '\\' + file_to_save_in
links_excel = openpyxl.load_workbook(filename=my_file)
sheet = links_excel['Sheet1']
for i in list_to_save:
sheet.append(i)
links_excel.save(filename)
links_excel.close()
return

Related

Is there a way to read the calcuated value in excel using openpyxl without data_only = True?

When I use data_only = True, it gets rid of all of the formulas and I don't want that. I just want it to be able to reference the actual calculated value and then do stuff with it. Then I want to be able to go back into the spreadsheet and have it work as it did before.
The only solution I can think of is to basically have python execute the command that excel does, but I don't even know if that's possible. For example if on Sheet1, cell A5 = "Sheet1!A1^2", would it be possible or practical to ask python to go into Sheet1A1 and grab the value from it?
I tried using data_only = True and it ruined my spreadsheet as it got rid of all the relationships between the cells.
So what I did is I opened the same workbook twice. Once as data_only = True the other as data_only = False. I only then saved the workbook that was data_only = False. That seemed to work.
Here's the relevant code:
import os, os.path
import openpyxl
import glob
Files = glob.glob('./*.csv')
directory_path = os.getcwd()
file_location = directory_path
file_name1 = "Navigator.xlsx"
path1 = file_location + "\\" + file_name1
wb = openpyxl.load_workbook(path1, data_only = False)
wbd = openpyxl.load_workbook(path1, data_only = True)
Worksheet1_Name = "NavLog"
Worksheet2_Name = "Departure-Arrival"
ws = wb[Worksheet1_Name]
wsd = wbd[Worksheet1_Name]
#Do whatever it is you want to do here
wb.save(file_name1)

openpyxl is overwriting any work done by win32 macro in Excel

I am currently writing a script that requires me to update data in an Excel sheet and run a macro. After running the macro, I am trying to save the file using win32, in order to be able to run through a similar process again. However, I have linked everything back to a weird issue with win32 and openpyxl. It seems that if I run the macro using win32, save the file and open it, everything looks exactly how it should. But if I then use openpyxl to add something to that file after running the macro, the entire results from the macro are then deleted. For example, the macro fills in cells A4:H23 with the correct data, but then after saving with win32 and reopening and editing with openpyxl, if I try to add any value to cell A3 afterwards and open up the file, the only thing that shows is the value in A3 and nothing that the macro should have done. I can open the sheet manually and add the number and resave it perfectly fine, but when I use openpyxl to do so, it clears all the macro results. I have included my code below for reference. Any help would be appreciated.
from openpyxl import load_workbook
import os
import win32com.client
import re
import time
Macro1 = r"C:\Users\...\Documents\Macro1Demo.xlsm"
Macro2 = r"C:\Users\...\Documents\Macro2Demo.xlsm"
MiddleManTest = r"C:\Users\...\Documents\MiddleManTest.xlsm"
MiddleMan2 = r"C:\Users\...\Documents\MiddleMan2.xlsm"
DistrictList = r"C:\Users\...\Documents\DistrictList.xlsx"
Macro1WB = load_workbook(filename = Macro1, keep_vba = True)
Macro2WB = load_workbook(filename = Macro2, keep_vba = True)
MM2WB = load_workbook(filename = MiddleMan2, keep_vba = True)
ListWB = load_workbook(filename = DistrictList, keep_vba = True)
ListSheet = ListWB['Sheet1']
M1Sheet = Macro1WB['Entry']
M2Sheet = Macro2WB['Raw']
for i in range(2,3):
Macro1WB['Entry']['A2'].value = ListWB['Sheet1']['A' + str(i)].value
Macro1WB['Entry']['B2'].value = ListWB['Sheet1']['B' + str(i)].value
OrgName = Macro1WB['Entry']['A2'].value
DistrictName = Macro1WB['Entry']['B2'].value
Macro1WB.save(Macro1)
SimpleOrgName = re.sub('[/\:*?<>|"]','',OrgName)
SimpleDistrictName = re.sub('[/\:*?<>|"]','',DistrictName)
NewFileName = SimpleOrgName + "(" + SimpleDistrictName + ")"
print(Macro1WB['Entry']['A2'].value,Macro1WB['Entry']['B2'].value)
print("Org/District Copied.")
if os.path.exists(r"C:\Users\...\Documents\Macro1Demo.xlsm"):
xl = win32com.client.Dispatch("Excel.application")
xl.visible = True
workbook = xl.Workbooks.Open(os.path.abspath(r"C:\Users\...\Documents\Macro1Demo.xlsm"))
xl.Application.Run("Macro1Demo.xlsm!Module1.AdvancedFilter")
print("Data filtered.")
workbook.SaveAs(MiddleMan2)
xl.Application.Quit()
MM2WB['Entry']['A3'] = i
MM2WB.save(MiddleMan2)

Python Excel Program Update Every Run

I have this simple code and it creates a file "example.xlsx"
I only need the A1 Cell to have an output for the first run.
This is my initial code
from openpyxl import Workbook
import requests
workbook = Workbook()
sheet = workbook.active
success= "DONE"
sheet["A1"] = requests.get('http://ip.42.pl/raw').text
workbook.save(filename="example.xlsx")
print(success)
The first output is an excel file example.xlsx. I am required to update the same excel file every time we run the program. Example.
The 1st run has only A1 with the output from the website http://ip.42.pl/raw and the following will be input to A2, A3 and so on every run.
THANK YOU. I AM BEGINNER. PLEASE BEAR WITH ME
I modified the code, and now I think it does what you ask for:
from openpyxl import Workbook, load_workbook
import os
import requests
workbook = Workbook()
filename = "example.xlsx"
success = "DONE"
# First verifies if the file exists
if os.path.exists(filename):
workbook = load_workbook(filename, read_only=False)
sheet = workbook.active
counter = 1
keep_going = True
while keep_going:
cell_id = 'A' + str(counter)
if sheet[cell_id].value is None:
sheet[cell_id] = requests.get('http://ip.42.pl/raw').text
keep_going = False
else:
counter += 1
workbook.save(filename)
print(success)
else:
# If file does not exist, you have to create an empty file from excel first
print('Please create an empty file ' + filename + ' from excel, as it throws error when created from openpyxl')
Check the question xlsx and xlsm files return badzipfile: file is not a zip file for clarification about why you have to create an empty file from excel so openpyxl can work with it (line in the else: statement).
You could use sheet.max_row in openpyxl to get the length. Like so:
from openpyxl import Workbook
import requests
workbook = Workbook()
sheet = workbook.active
max_row = sheet.max_row
success= "DONE"
sheet.cell(row=max_row+1, column=1).value = requests.get('http://ip.42.pl/raw').text
# sheet["A1"] = requests.get('http://ip.42.pl/raw').text
workbook.save(filename="example.xlsx")
print(success)

For Loop Skips last List

I have a for loop statement that when executes always creates one less excel than the list has. However when the first part of the if statement is used (xlwings, to modify the existing excels it works fine) Thoughts?
names= list(df_ora['XCODE'].unique())
for prov in names:
#for each matching agency code we create a df2
df2 = df_ora[df_ora['CODE'].isin([prov,'00000'])]
# create a filename to verify the excel exisits
filename = (dir_src + '\\' + str(prov) + '_' + 'Claims' + '.xlsx')
if os.path.isfile(filename):
wb = xw.Book(filename)
ws = wb.sheets['DATA']
ws.clear_contents()
ws.range('A1').options(index=False).value = df2
ws.autofit()
wb = xw.Book(filename)
wb.save()
xw.apps[0].quit()
counter = counter + 1
else:
writer = pd.ExcelWriter(filename, engine='xlsxwriter')
df2.to_excel(writer, sheet_name='DATA',index=False)
counter = counter + 1
Try closing the writer, or writer.save(), right after df2.to_excel(writer, sheet_name='DATA',index=False). The writer's content is probably not flushed to disk until it's either explicitly closed or goes out of scope.

How do I save a workbook using xlwings?

I have an excel worksheet, some buttons and some macros. I use xlwings to make it work. Is there a way to save the workbook through xlwings ? I want to extract a specific sheet after doing an operation, but the saved sheet is the extracted sheet before the operation without the generated data.
My code for extracting the sheet I need is the following:
Set objFSO = CreateObject("Scripting.FileSystemObject")
src_file = objFSO.GetAbsolutePathName(Wscript.Arguments.Item(0))
sheet_name = Wscript.Arguments.Item(1)
dir_name = Wscript.Arguments.Item(2)
file_name = Wscript.Arguments.Item(3)
Dim objExcel
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
Dim objWorkbook
Set objWorkbook = objExcel.Workbooks(src_file)
objWorkbook.Sheets(sheet_name).Copy
objExcel.DisplayAlerts = False
objExcel.ActiveWorkbook.SaveAs dir_name + file_name + ".xlsx", 51
objExcel.ActiveWorkbook.SaveAs dir_name + file_name + ".csv", 6
objWorkbook.Close False
objExcel.Quit
Book.save() has now been implemented: see the docs.

Categories