2

I am trying to find the date of the newest file in a directory, based on some Python code I shamelessly found on this site.

def newest_file_in_tree(rootfnewer, extension=".avi"):
    return max(
        (os.path.join(dirname, filename)
        for dirname, dirnames, filenames in os.walk(rootfnewer)
        for filename in filenames
        if filename.endswith(extension)),
        key=lambda fn: os.stat(fn).st_mtime)

This works, but fails on empty directories.

    key=lambda fn: os.stat(fn).st_mtime)
ValueError: max() arg is an empty sequence

I concede that I am a Python beginner, and the last line is way beyond my pay grade.

Can anyone suggest how I can trap the error and prevent the function from crashing?

2 Answers 2

7

max has a default keyword:

m = max([], key=lambda x: abs(x), default='empty...')
print(m) # 'empty...'

the default will be returned if the iterable is empty. without the default this would raise a ValueError.


a different way for you to go would be to use glob in order to list the files:

import os
from glob import glob

def newest_file_in_tree(rootdir, ext='.avi'):
    glob_wildcard = os.path.join(rootdir, '**/*{}'.format(ext))
    glob_gen = glob(glob_wildcard, recursive=True)
    return max(glob_gen, key=lambda fn: os.stat(fn).st_mtime, default='?')

or even more concise with pathlib:

from pathlib import Path

def newest_file_in_tree(rootpath, ext='.avi'):
    return max(Path(rootpath).glob('**/*{}'.format(ext)),
               key=lambda pth: pth.stat().st_mtime, default='?')
Sign up to request clarification or add additional context in comments.

2 Comments

Cool. Did not know this.
Thanks, I tested this and it worked, but I normally use Python 2 (macOS does not come with Python3 by default!) which does not have the default (also not mentioned in Learning Python)
4

You can separate out that monstrously pythonic one liner into two separate lines, to make sure that max is called only when you have a non-empty list of files from which you pick the newest one:

def newest_file_in_tree(rootfnewer, extension=".avi"):
    files = [
        os.path.join(dirname, filename)
        for dirname, dirnames, filenames in os.walk(rootfnewer)
        for filename in filenames
        if filename.endswith(extension)
    ]

    if files:
        return max(files, key=lambda fn: os.stat(fn).st_mtime)

    return None

Not as pretty as @hiroprotagonist's solution, but is more readable.

3 Comments

@TimPietzcker Yesss! Testing the truthiness of an empty list. Updated, thank you.
I like this because it unclutters the code and is nicely explicit about what is happening.
@TimPietzcker Agreed. An even nicer (albeit less pythonic) solution would be removing the nested loops from that comprehension!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.