Skip to content

Commit 907e192

Browse files
committed
fixes #807
1 parent de8691d commit 907e192

4 files changed

Lines changed: 119 additions & 385 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
<!-- do not remove -->
44

5+
## 1.12.41
6+
7+
8+
9+
510
## 1.12.40
611

712
### New Features

fastcore/_modidx.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,4 +868,5 @@
868868
'fastcore.xtras.untar_dir': ('xtras.html#untar_dir', 'fastcore/xtras.py'),
869869
'fastcore.xtras.utc2local': ('xtras.html#utc2local', 'fastcore/xtras.py'),
870870
'fastcore.xtras.vars_pub': ('xtras.html#vars_pub', 'fastcore/xtras.py'),
871-
'fastcore.xtras.walk': ('xtras.html#walk', 'fastcore/xtras.py')}}}
871+
'fastcore.xtras.walk': ('xtras.html#walk', 'fastcore/xtras.py'),
872+
'fastcore.xtras.walk_join': ('xtras.html#walk_join', 'fastcore/xtras.py')}}}

fastcore/xtras.py

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_xtras.ipynb.
44

55
# %% auto #0
6-
__all__ = ['spark_chars', 'UNSET', 'walk', 'exttypes', 'globtastic', 'pglob', 'maybe_open', 'mkdir', 'image_size', 'img_bytes',
7-
'detect_mime', 'bunzip', 'loads', 'loads_multi', 'dumps', 'untar_dir', 'repo_details', 'shell', 'ssh',
8-
'rsync_multi', 'run', 'open_file', 'save_pickle', 'load_pickle', 'parse_env', 'expand_wildcards',
6+
__all__ = ['spark_chars', 'UNSET', 'walk_join', 'walk', 'exttypes', 'globtastic', 'pglob', 'maybe_open', 'mkdir', 'image_size',
7+
'img_bytes', 'detect_mime', 'bunzip', 'loads', 'loads_multi', 'dumps', 'untar_dir', 'repo_details', 'shell',
8+
'ssh', 'rsync_multi', 'run', 'open_file', 'save_pickle', 'load_pickle', 'parse_env', 'expand_wildcards',
99
'atomic_save', 'dict2obj', 'obj2dict', 'repr_dict', 'is_listy', 'mapped', 'IterLen', 'ReindexCollection',
1010
'SaveReturn', 'trim_wraps', 'save_iter', 'asave_iter', 'frontmatter', 'clean_cli_output', 'unqid',
1111
'rtoken_hex', 'friendly_name', 'n_friendly_names', 'exec_eval', 'get_source_link', 'sparkline',
@@ -33,25 +33,36 @@
3333
from dataclasses import dataclass, field, fields, is_dataclass, MISSING, make_dataclass
3434

3535
# %% ../nbs/03_xtras.ipynb #f64c2b09
36+
def walk_join(root, name):
37+
return (p:=os.path.join(root, name)) + ('/' if os.path.isdir(p) else '')
38+
39+
# %% ../nbs/03_xtras.ipynb #33decc5e
3640
def walk(
3741
path:Path|str, # path to start searching
3842
symlinks:bool=True, # follow symlinks?
3943
keep_file:callable=ret_true, # function that returns True for wanted files
4044
keep_folder:callable=ret_true, # function that returns True for folders to enter
4145
skip_folder:callable=ret_false, # function that returns True for folders to skip
42-
func:callable=os.path.join, # function to apply to each matched file
43-
ret_folders:bool=False, # return folders, not just files
44-
sort:bool=True # sort files by name within each folder
46+
func:callable=walk_join, # function applied to each entry; default adds `/` to folders
47+
ret_folders:bool=False, # include folder entries inline with files?
48+
sort:bool=True, # sort entries alphabetically within each folder?
49+
maxdepth:int=None, # max depth to descend (1=just immediate contents; None=unlimited)
4550
):
46-
"Generator version of `os.walk`, using functions to filter files and folders"
47-
from copy import copy
48-
for root,dirs,files in os.walk(path, followlinks=symlinks):
49-
if keep_folder(root,''):
50-
if ret_folders: yield func(root, '')
51-
if sort: files = sorted(files)
52-
yield from (func(root, name) for name in files if keep_file(root,name))
53-
for name in copy(dirs):
54-
if skip_folder(root,name): dirs.remove(name)
51+
"Generator: yields files and (optionally) folders as unified, inline-sorted entries"
52+
path = Path(path)
53+
def _walk(root, depth):
54+
try: entries = list(os.scandir(root))
55+
except OSError: return
56+
if sort: entries.sort(key=lambda e: e.name)
57+
at_max = maxdepth is not None and depth >= maxdepth-1
58+
for e in entries:
59+
if e.is_dir(follow_symlinks=symlinks):
60+
if skip_folder(root, e.name): continue
61+
keep = keep_folder(root, e.name)
62+
if ret_folders and keep: yield func(root, e.name)
63+
if keep and not at_max: yield from _walk(e.path, depth+1)
64+
elif keep_file(root, e.name): yield func(root, e.name)
65+
yield from _walk(str(path), 0)
5566

5667
# %% ../nbs/03_xtras.ipynb #12a01ff4
5768
_exttypes = dict(
@@ -79,14 +90,15 @@ def exttypes(types):
7990
def globtastic(
8091
path:Path|str='.', # path to start searching
8192
recursive:bool=True, # search subfolders
93+
maxdepth:int=None, # max depth to descend (1=just immediate contents; None=unlimited)
8294
symlinks:bool=True, # follow symlinks?
8395
file_glob:str=None, # Only include files matching glob
8496
file_re:str=None, # Only include files matching regex
8597
folder_re:str=None, # Only enter folders matching regex
8698
skip_file_glob:str=None, # Skip files matching glob
8799
skip_file_re:str=None, # Skip files matching regex
88100
skip_folder_re:str=None, # Skip folders matching regex,
89-
func:callable=os.path.join, # function to apply to each matched file
101+
func:callable=walk_join, # function to apply to each matched file
90102
ret_folders:bool=False, # return folders, not just files
91103
sort:bool=True, # sort files by name within each folder
92104
types:str|list=None, # list or comma-separated str of ext types from: py, js, java, c, cpp, rb, r, ex, sh, web, doc, cfg
@@ -111,8 +123,8 @@ def _keep_file(root, name):
111123
not skip_file_re or not skip_file_re.search(name))
112124
def _keep_folder(root, name): return not folder_re or folder_re.search(os.path.join(root,name))
113125
def _skip_folder(root, name): return skip_folder_re and skip_folder_re.search(name)
114-
return L(walk(path, symlinks=symlinks, keep_file=_keep_file, keep_folder=_keep_folder, skip_folder=_skip_folder,
115-
func=func, ret_folders=ret_folders, sort=sort))
126+
return L(walk(path, symlinks=symlinks, maxdepth=maxdepth, keep_file=_keep_file, keep_folder=_keep_folder,
127+
skip_folder=_skip_folder, func=func, ret_folders=ret_folders, sort=sort))
116128

117129
# %% ../nbs/03_xtras.ipynb #827b4914
118130
@fdelegates(globtastic)
@@ -447,8 +459,9 @@ def repr_dict(d):
447459

448460
# %% ../nbs/03_xtras.ipynb #20842e1f
449461
def is_listy(x):
450-
"`isinstance(x, (tuple,list,L,slice,Generator))`"
451-
return isinstance(x, (tuple,list,L,slice,Generator))
462+
"`isinstance(x, (tuple,list,L,slice,Generator,set,frozenset))`"
463+
return isinstance(x, (tuple,list,L,slice,Generator,set,frozenset))
464+
452465

453466
# %% ../nbs/03_xtras.ipynb #40c2c641
454467
def mapped(f, it):

0 commit comments

Comments
 (0)