saving file doesn't update last_modified user and datetime
Saving File doesn't update last modified user and datetime
Version Info
- openpyxl version: 3.0.10
- python version: 3.11.2
- os: Windows 10
Issue
Excel uses /docProps/core.xml to store metadata including modified (with a datetime) and lastModifiedBy (username). This is used by Excel itself in 'Info' as well as by the OS (at least by Windows) to show details on the file. When you open a file with Excel itself and save the file, these two fields get updated appropriately. When you use wb.save(...)
, they do not get updated.
We have scripts that use openpyxl to create/modify excel files from existing base files, and the metadata on all the new files is just the original metadata from the base file, masking when the update was done and who ran it.
Recreate
Create an Excel file (I created mine from Excel itself) and save it. Wait a minute or two and then open with openpyxl and save it, and you'll see that the modified field is not updated (or the user, but a little harder to test that all by yourself).
If you create the file from openpyxl itself (wb = openpyxl.WB()
), the last user to modify will not get populated at all, and won't get updated same as above.
Relevant Code
I'm not a pro with openpyxl, but it appears the relevant code is in openpyxl/writer/excel.py.ExcelWriter.write_data()
def write_data(self):
"""Write the various xml files into the zip archive."""
# cleanup all worksheets
archive = self._archive
props = ExtendedProperties()
archive.writestr(ARC_APP, tostring(props.to_tree()))
archive.writestr(ARC_CORE, tostring(self.workbook.properties.to_tree()))
...
In the call here to archive.writestr(ARC_CORE, tostring(self.workbook.properties.to_tree()))
, it doesn't look like anything is being done to get the current datetime or current user and use those values. Instead, it looks like it just reads that the existing properties are for the workbook and re-saves those. I don't see anywhere else where workbook.properties
is modified.
Another potential relevant spot is in in openpyxl/reader/excel.py.ExcelReader.read_properties().
def read_properties(self):
if ARC_CORE in self.valid_files:
src = fromstring(self.archive.read(ARC_CORE))
self.wb.properties = DocumentProperties.from_tree(src)
This is called after using wb.load_workbook()
, and looks like it sets wb.properties
to what the existing DocumentProperties already are. That's probably correct for reading at this point.
Potential Fix
In the above call to archive.writestr(ARC_CORE, tostring(self.workbook.properties.to_tree()))
, first update the workbook properties.
workbook.properties is a DocumentProperties
object (openpyxl/packaging/core.py.DocumentProperties). I don't see an easy API to update any of the properties of DocumentProperties, but may be as easy (ha, like anything is easy) as setting wb.properties.modifed = datetime.datetime.utcnow()
and wb.properties.lastModifiedBy
to the user (not sure best way to do this).
So that it won't break/change existing behavior, it may make sense to add a parameter to wb.save(...update_metadata:bool = False)
.