Timestamp Preserving Output File Writer

API

Timestamp Preserving Output File Writer.

outputfile.open_ behaves identical to open(..., mode="w"):

>>> from outputfile import open_
>>> from pathlib import Path
>>> filepath = Path('file.txt')
>>> with open_(filepath) as file:
...     file.write("foo")

but the timestamp stays the same, if the file content did not change:

>>> mtime = filepath.stat().st_mtime
>>> with open_(filepath) as file:
...     file.write("foo")
>>> mtime - filepath.stat().st_mtime
0.0

The state attribute details the file handling status:

>>> otherpath = Path('other.txt')
>>> # first write
>>> with open_(otherpath) as file:
...     file.write("foo")
>>> file.state.name
'CREATED'
>>> # same write
>>> with open_(otherpath) as file:
...     file.write("foo")
>>> file.state.name
'IDENTICAL'
>>> # other write
>>> with open_(otherpath) as file:
...     file.write("bar")
>>> file.state.name
'UPDATED'

The argument existing defines the update strategy and can Existing.KEEP

>>> keep = Path('keep.txt')
>>> # first write
>>> with open_(keep, existing=Existing.KEEP) as file:
...     file.write("foo")
>>> file.state.name
'CREATED'
>>> # same write
>>> with open_(keep, existing=Existing.KEEP) as file:
...     file.write("foo")
>>> file.state.name
'EXISTING'
>>> # other write
>>> with open_(keep, existing=Existing.KEEP) as file:
...     file.write("bar")
>>> file.state.name
'EXISTING'

… or Existing.OVERWRITE

>>> overwrite = Path('overwrite.txt')
>>> # first write
>>> with open_(overwrite, existing=Existing.OVERWRITE) as file:
...     file.write("foo")
>>> file.state.name
'CREATED'
>>> # same write
>>> with open_(overwrite, existing=Existing.OVERWRITE) as file:
...     file.write("foo")
>>> file.state.name
'OVERWRITTEN'
>>> # other write
>>> with open_(overwrite, existing=Existing.OVERWRITE) as file:
...     file.write("bar")
>>> file.state.name
'OVERWRITTEN'
class outputfile.Existing(value)[source]

Bases: Enum

Strategy for Handling of existing files.

ERROR = 'error'
KEEP = 'keep'
KEEP_TIMESTAMP = 'keep_timestamp'
OVERWRITE = 'overwrite'
class outputfile.OutputFile(filepath: Union[Path, str], existing: Union[Existing, str] = Existing.KEEP_TIMESTAMP, mkdir: bool = False, diffout=None, kwargs=None)[source]

Bases: object

File Object Wrapper.

close()[source]

Close the file.

property closed

True, when the file has been closed and is not writable anymore.

flush()[source]

Flush file content.

property state

State.

write(*args, **kwargs)[source]

Write to file.

See io.TextIOBase.write() for reference.

Returns:

None

Raises:

ValueError – when the file is already closed.

class outputfile.State(value)[source]

Bases: Enum

File state.

CREATED = 'CREATED.'
EXISTING = 'existing. SKIPPED.'
FAILED = 'FAILED.'
IDENTICAL = 'identical. untouched.'
OPEN = 'OPEN'
OVERWRITTEN = 'OVERWRITTEN.'
UPDATED = 'UPDATED.'
outputfile.open_(filepath: Union[Path, str], existing: Union[Existing, str] = Existing.KEEP_TIMESTAMP, mkdir: bool = False, diffout=None, **kwargs)[source]

Return an output file handle, whose timestamp is only updated on content change.

By default, the filesystem timestamp of a written file is always updated on write, also when the final file content is identical to the overwritten version. The OutputFile class works around this rule.

The OutputFile class behaves like a normal file in write (‘w’) mode, but the output is written to a temporary file. On close() the temporary file and the target file are compared. If both files are identical, the temporary file is removed. If they differ, the temporary file is moved to the target file location.

Parameters:

filepath (str) – Path to the target file.

Keyword Arguments:
  • existing (Existing, str) –

    Handling of existing output files:

  • mkdir (bool) – create the output directory if it not exists.

  • diffout – function receiving file diff on update.

Raises:

FileExistsError – if existing=”error” and file exists already.

Any keyword argument is simply bypassed to the “open” function, except “mode”, which is forced to “w”.

Indices and tables