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' ,
3333from 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
3640def 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):
7990def 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
449461def 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
454467def mapped (f , it ):
0 commit comments