abstract-utilities 0.2.2.513__py3-none-any.whl → 0.2.2.583__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. abstract_utilities/class_utils/caller_utils.py +18 -0
  2. abstract_utilities/class_utils/global_utils.py +3 -2
  3. abstract_utilities/class_utils/imports/imports.py +1 -1
  4. abstract_utilities/directory_utils/__init__.py +2 -4
  5. abstract_utilities/directory_utils/imports/__init__.py +2 -0
  6. abstract_utilities/directory_utils/imports/imports.py +1 -0
  7. abstract_utilities/directory_utils/imports/module_imports.py +2 -0
  8. abstract_utilities/directory_utils/src/__init__.py +4 -0
  9. abstract_utilities/directory_utils/src/directory_utils.py +108 -0
  10. abstract_utilities/directory_utils/src/name_utils.py +43 -0
  11. abstract_utilities/directory_utils/src/size_utils.py +57 -0
  12. abstract_utilities/directory_utils/src/utils.py +116 -0
  13. abstract_utilities/file_utils/imports/constants.py +81 -7
  14. abstract_utilities/file_utils/imports/imports.py +0 -4
  15. abstract_utilities/file_utils/imports/module_imports.py +1 -1
  16. abstract_utilities/file_utils/src/__init__.py +2 -4
  17. abstract_utilities/file_utils/src/file_filters/__init__.py +4 -0
  18. abstract_utilities/file_utils/src/file_filters/ensure_utils.py +116 -0
  19. abstract_utilities/file_utils/src/file_filters/filter_params.py +86 -0
  20. abstract_utilities/file_utils/src/file_filters/filter_utils.py +78 -0
  21. abstract_utilities/file_utils/src/file_filters/predicate_utils.py +114 -0
  22. abstract_utilities/file_utils/src/file_filters.py +114 -47
  23. abstract_utilities/file_utils/src/file_reader.py +0 -64
  24. abstract_utilities/file_utils/src/file_utils.py +7 -130
  25. abstract_utilities/file_utils/src/filter_params.py +128 -86
  26. abstract_utilities/file_utils/src/find_collect.py +85 -165
  27. abstract_utilities/file_utils/src/find_content.py +210 -0
  28. abstract_utilities/file_utils/src/initFunctionsGen.py +3 -9
  29. abstract_utilities/file_utils/src/reader_utils/__init__.py +4 -0
  30. abstract_utilities/file_utils/src/reader_utils/directory_reader.py +53 -0
  31. abstract_utilities/file_utils/src/reader_utils/file_reader.py +543 -0
  32. abstract_utilities/file_utils/src/reader_utils/file_readers.py +376 -0
  33. abstract_utilities/file_utils/src/reader_utils/imports.py +18 -0
  34. abstract_utilities/file_utils/src/reader_utils/pdf_utils.py +300 -0
  35. abstract_utilities/file_utils (2)/__init__.py +2 -0
  36. abstract_utilities/file_utils (2)/imports/__init__.py +2 -0
  37. abstract_utilities/file_utils (2)/imports/constants.py +118 -0
  38. abstract_utilities/file_utils (2)/imports/imports/__init__.py +3 -0
  39. abstract_utilities/file_utils (2)/imports/imports/constants.py +119 -0
  40. abstract_utilities/file_utils (2)/imports/imports/imports.py +46 -0
  41. abstract_utilities/file_utils (2)/imports/imports/module_imports.py +8 -0
  42. abstract_utilities/file_utils (2)/imports/utils/__init__.py +3 -0
  43. abstract_utilities/file_utils (2)/imports/utils/classes.py +379 -0
  44. abstract_utilities/file_utils (2)/imports/utils/clean_imps.py +155 -0
  45. abstract_utilities/file_utils (2)/imports/utils/filter_utils.py +341 -0
  46. abstract_utilities/file_utils (2)/src/__init__.py +8 -0
  47. abstract_utilities/file_utils (2)/src/file_filters.py +155 -0
  48. abstract_utilities/file_utils (2)/src/file_reader.py +604 -0
  49. abstract_utilities/file_utils (2)/src/find_collect.py +258 -0
  50. abstract_utilities/file_utils (2)/src/initFunctionsGen.py +286 -0
  51. abstract_utilities/file_utils (2)/src/map_utils.py +28 -0
  52. abstract_utilities/file_utils (2)/src/pdf_utils.py +300 -0
  53. abstract_utilities/import_utils/circular_import_finder.py +222 -0
  54. abstract_utilities/import_utils/circular_import_finder2.py +118 -0
  55. abstract_utilities/import_utils/imports/module_imports.py +3 -1
  56. abstract_utilities/import_utils/src/clean_imports.py +156 -25
  57. abstract_utilities/import_utils/src/dot_utils.py +11 -0
  58. abstract_utilities/import_utils/src/extract_utils.py +4 -0
  59. abstract_utilities/import_utils/src/import_functions.py +47 -2
  60. abstract_utilities/import_utils/src/pkg_utils.py +58 -4
  61. abstract_utilities/import_utils/src/sysroot_utils.py +56 -1
  62. abstract_utilities/log_utils/log_file.py +3 -2
  63. abstract_utilities/path_utils/path_utils.py +25 -23
  64. abstract_utilities/safe_utils/safe_utils.py +30 -0
  65. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.583.dist-info}/METADATA +1 -1
  66. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.583.dist-info}/RECORD +68 -28
  67. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.583.dist-info}/WHEEL +0 -0
  68. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.583.dist-info}/top_level.txt +0 -0
@@ -5,68 +5,78 @@ def combine_params(*values,typ=None):
5
5
  nu_values = None
6
6
  for value in values:
7
7
  if value is not None:
8
+ typ = typ or type(value)
8
9
  if nu_values is None:
9
- typ = typ or type(value)
10
10
  nu_values = typ()
11
- else:
12
- if val_type is set:
13
- nu_values = nu_values | typ(value)
14
- if val_type is list:
15
- nu_values += typ(value)
11
+
12
+ if typ is set:
13
+ nu_values = nu_values | typ(value)
14
+ if typ is list:
15
+ nu_values += typ(value)
16
16
  return nu_values
17
- # -------------------------
18
- # Default sets
19
- # -------------------------
20
-
21
- DEFAULT_ALLOWED_EXTS: Set[str] = {
22
- ".py", ".pyw", ".js", ".jsx", ".ts", ".tsx", ".mjs",
23
- ".html", ".htm", ".xml", ".css", ".scss", ".sass", ".less",
24
- ".json", ".yaml", ".yml", ".toml", ".ini", ".cfg",
25
- ".md", ".markdown", ".rst", ".sh", ".bash", ".env", ".txt"
26
- }
27
-
28
- DEFAULT_EXCLUDE_TYPES: Set[str] = {
29
- "image", "video", "audio", "presentation",
30
- "spreadsheet", "archive", "executable"
31
- }
32
-
33
- _unallowed = set(get_media_exts(DEFAULT_EXCLUDE_TYPES)) | {
34
- ".bak", ".shp", ".cpg", ".dbf", ".shx", ".geojson",
35
- ".pyc", ".prj", ".sbn", ".sbx"
36
- }
37
- DEFAULT_UNALLOWED_EXTS = {e for e in _unallowed if e not in DEFAULT_ALLOWED_EXTS}
38
-
39
- DEFAULT_EXCLUDE_DIRS: List[str] = [
40
- "node_modules", "__pycache__", "backups", "backup",
41
- "trash", "deprecated", "old", "__init__"
42
- ]
43
-
44
- DEFAULT_EXCLUDE_PATTERNS: List[str] = [
45
- "__init__*", "*.tmp", "*.log", "*.lock", "*.zip", "*~"
46
- ]
47
-
48
- DEFAULT_ALLOWED_PATTERNS: List[str] = ["*"]
49
- DEFAULT_ALLOWED_DIRS: List[str] = ["*"]
50
- DEFAULT_ALLOWED_TYPES: List[str] = ["*"]
51
-
52
- REMOTE_RE = re.compile(r"^(?P<host>[^:\s]+@[^:\s]+):(?P<path>/.*)$")
53
- AllowedPredicate = Optional[Callable[[str], bool]]
54
-
55
- # -------------------------
56
- # Config dataclass
57
- # -------------------------
17
+ def get_safe_kwargs(canonical_map, **kwargs):
18
+ # Lowercase all keys for safety
19
+ canonical_map = canonical_map or CANONICAL_MAP
20
+ norm_kwargs = {k.lower(): v for k, v in kwargs.items() if v is not None}
21
+
22
+ # Inverse lookup: alias canonical key
23
+ alias_lookup = {
24
+ alias: canon
25
+ for canon, aliases in canonical_map.items()
26
+ if aliases
27
+ for alias in aliases
28
+ }
58
29
 
59
- @dataclass
60
- class ScanConfig:
61
- allowed_exts: Set[str]
62
- unallowed_exts: Set[str]
63
- allowed_types: Set[str]
64
- exclude_types: Set[str]
65
- allowed_dirs: List[str] = field(default_factory=list)
66
- exclude_dirs: List[str] = field(default_factory=list)
67
- allowed_patterns: List[str] = field(default_factory=list)
68
- exclude_patterns: List[str] = field(default_factory=list)
30
+ # Preserve correctly named keys
31
+ safe_kwargs = {k: v for k, v in norm_kwargs.items() if k in canonical_map}
69
32
 
33
+ for k, v in norm_kwargs.items():
34
+ if k in alias_lookup:
35
+ canonical_key = alias_lookup[k]
36
+ prev = safe_kwargs.get(canonical_key)
37
+ if prev is None:
38
+ safe_kwargs[canonical_key] = v
39
+ else:
40
+ # merge intelligently if both exist
41
+ if isinstance(prev, (set, list)) and isinstance(v, (set, list)):
42
+ safe_kwargs[canonical_key] = list(set(prev) | set(v))
43
+ else:
44
+ safe_kwargs[canonical_key] = v # overwrite for non-iterables
45
+
46
+ # fill defaults if missing
47
+ for canon in canonical_map:
48
+ safe_kwargs.setdefault(canon, None)
49
+
50
+ return safe_kwargs
51
+
52
+ def create_canonical_map(*args,canonical_map=None):
53
+ keys = [arg for arg in args if arg]
54
+ if not keys:
55
+ return CANONICAL_MAP
56
+ canonical_map = canonical_map or CANONICAL_MAP
57
+
58
+ return {key:canonical_map.get(key) for key in keys}
59
+ def get_safe_canonical_kwargs(*args,canonical_map=None,**kwargs):
60
+ canonical_map = canonical_map or create_canonical_map(*args)
61
+
62
+ return get_safe_kwargs(canonical_map=canonical_map,**kwargs)
63
+ def get_dir_filter_kwargs(**kwargs):
64
+ canonical_map = create_canonical_map("directories")
65
+ return get_safe_kwargs(canonical_map=canonical_map,**kwargs)
66
+ def get_file_filter_kwargs(**kwargs):
67
+ """
68
+ Normalize arbitrary keyword arguments for file scanning configuration.
69
+
70
+ Examples:
71
+ - 'excluded_ext' or 'unallowed_exts' → 'exclude_exts'
72
+ - 'include_dirs' or 'allow_dir' → 'allowed_dirs'
73
+ - 'excludePattern' or 'excluded_patterns' → 'exclude_patterns'
74
+ - 'allowed_type' or 'include_types' → 'allowed_types'
75
+ """
76
+ # Canonical keys and aliases
77
+ canonical_keys =["allowed_exts","exclude_exts","allowed_types","exclude_types","allowed_dirs","exclude_dirs","allowed_patterns","exclude_patterns"]
78
+
79
+ return get_safe_canonical_kwargs(*canonical_keys,**kwargs)
70
80
  # -------------------------
71
81
  # Utility functions
72
82
  # -------------------------
@@ -110,10 +120,12 @@ def ensure_patterns(patterns):
110
120
 
111
121
  def _get_default_modular(value, default, add=False, typ=set):
112
122
  """Merge user and default values intelligently."""
113
- if value in [True, None]:
123
+ if value == None:
124
+ value = add
125
+ if value in [True]:
114
126
  return default
115
127
  if value is False:
116
- return typ()
128
+ return value
117
129
  if add:
118
130
  return combine_params(value,default,typ=None)
119
131
 
@@ -122,33 +134,63 @@ def _get_default_modular(value, default, add=False, typ=set):
122
134
  # -------------------------
123
135
  # Default derivation logic
124
136
  # -------------------------
125
-
126
- def derive_file_defaults(
127
- allowed_exts=False, unallowed_exts=False,
128
- allowed_types=False, exclude_types=False,
129
- allowed_dirs=False, exclude_dirs=False,
130
- allowed_patterns=False, exclude_patterns=False,
131
- add=False
132
- ):
133
- allowed_exts = _get_default_modular(ensure_exts(allowed_exts), DEFAULT_ALLOWED_EXTS, add, set)
134
- unallowed_exts = _get_default_modular(ensure_exts(unallowed_exts), DEFAULT_UNALLOWED_EXTS, add, set)
135
- allowed_types = _get_default_modular(_normalize_listlike(allowed_types, set), DEFAULT_ALLOWED_TYPES, add, set)
136
- exclude_types = _get_default_modular(_normalize_listlike(exclude_types, set), DEFAULT_EXCLUDE_TYPES, add, set)
137
- allowed_dirs = _get_default_modular(_normalize_listlike(allowed_dirs, list), DEFAULT_ALLOWED_DIRS, add, list)
138
- exclude_dirs = _get_default_modular(_normalize_listlike(exclude_dirs, list), DEFAULT_EXCLUDE_DIRS, add, list)
139
- allowed_patterns = _get_default_modular(ensure_patterns(allowed_patterns), DEFAULT_ALLOWED_PATTERNS, add, list)
140
- exclude_patterns = _get_default_modular(ensure_patterns(exclude_patterns), DEFAULT_EXCLUDE_PATTERNS, add, list)
141
-
142
- return {
143
- "allowed_exts": allowed_exts,
144
- "unallowed_exts": unallowed_exts,
145
- "allowed_types": allowed_types,
146
- "exclude_types": exclude_types,
147
- "allowed_dirs": allowed_dirs,
148
- "exclude_dirs": exclude_dirs,
149
- "allowed_patterns": allowed_patterns,
150
- "exclude_patterns": exclude_patterns,
151
- }
137
+ def _get_default_modular(value, default, add=None, typ=set):
138
+ """Merge user and default values intelligently."""
139
+ add = add or False
140
+ if value == None:
141
+ value = add
142
+ if value in [True]:
143
+ return default
144
+ if value is False:
145
+ return value
146
+ if add:
147
+ return combine_params(value,default,typ=None)
148
+ return typ(value)
149
+ def derive_all_defaults(**kwargs):
150
+ kwargs = get_safe_canonical_kwargs(**kwargs)
151
+ add = kwargs.get("add",False)
152
+ nu_defaults = {}
153
+ for key,values in DEFAULT_CANONICAL_MAP.items():
154
+ default = values.get("default")
155
+ typ = values.get("type")
156
+ key_value = kwargs.get(key)
157
+ if key in DEFAULT_ALLOWED_EXCLUDE_MAP:
158
+
159
+ if key.endswith('exts'):
160
+ input_value = ensure_exts(key_value)
161
+ if key.endswith('patterns'):
162
+ input_value = ensure_patterns(key_value)
163
+ else:
164
+ input_value = _normalize_listlike(key_value, typ)
165
+ nu_defaults[key] = _get_default_modular(input_value, default, add, typ)
166
+ else:
167
+ value = default if key_value is None else key_value
168
+ if typ == list:
169
+ value = make_list(value)
170
+ elif typ == bool:
171
+ value = bool(value)
172
+ nu_defaults[key] = value
173
+
174
+ return nu_defaults
175
+ # -------------------------
176
+ # Default derivation logic
177
+ # -------------------------
178
+ def derive_file_defaults(**kwargs):
179
+ kwargs = derive_all_defaults(**kwargs)
180
+ add = kwargs.get("add",False)
181
+ nu_defaults = {}
182
+ for key,values in DEFAULT_ALLOWED_EXCLUDE_MAP.items():
183
+ default = values.get("default")
184
+ typ = values.get("type")
185
+ key_value = kwargs.get(key)
186
+ if key.endswith('exts'):
187
+ input_value = ensure_exts(key_value)
188
+ if key.endswith('patterns'):
189
+ input_value = ensure_patterns(key_value)
190
+ else:
191
+ input_value = _normalize_listlike(key_value, typ)
192
+ nu_defaults[key] = _get_default_modular(input_value, default, add, typ)
193
+ return nu_defaults
152
194
 
153
195
  def define_defaults(**kwargs):
154
196
  defaults = derive_file_defaults(**kwargs)
@@ -1,79 +1,15 @@
1
1
  from ..imports import *
2
- from .filter_params import *
3
- from .file_filters import enumerate_source_files
2
+ from .file_filters import *
4
3
  from pathlib import Path
5
4
  from typing import Optional, List, Set
6
5
 
7
- def check_path_type(
8
- path: str,
9
- user: Optional[str] = None,
10
- host: Optional[str] = None,
11
- user_as_host: Optional[str] = None,
12
- use_shell: bool = False
13
- ) -> Literal["file", "directory", "missing", "unknown"]:
14
- """
15
- Determine whether a given path is a file, directory, or missing.
16
- Works locally or remotely (via SSH).
17
6
 
18
- Args:
19
- path: The path to check.
20
- user, host, user_as_host: SSH parameters if remote.
21
- use_shell: Force shell test instead of Python os.path.
22
- Returns:
23
- One of: 'file', 'directory', 'missing', or 'unknown'
24
- """
25
-
26
- # --- remote check if user/host is given ---
27
- if user_as_host or (user and host):
28
- remote_target = user_as_host or f"{user}@{host}"
29
- cmd = f"if [ -f '{path}' ]; then echo file; elif [ -d '{path}' ]; then echo directory; else echo missing; fi"
30
- try:
31
- result = subprocess.check_output(
32
- ["ssh", remote_target, cmd],
33
- stderr=subprocess.DEVNULL,
34
- text=True,
35
- timeout=5
36
- ).strip()
37
- return result if result in ("file", "directory", "missing") else "unknown"
38
- except Exception:
39
- return "unknown"
40
-
41
- # --- local check ---
42
- if not use_shell:
43
- if os.path.isfile(path):
44
- return "file"
45
- elif os.path.isdir(path):
46
- return "directory"
47
- elif not os.path.exists(path):
48
- return "missing"
49
- return "unknown"
50
- else:
51
- # fallback using shell tests (useful for sandboxed contexts)
52
- cmd = f"if [ -f '{path}' ]; then echo file; elif [ -d '{path}' ]; then echo directory; else echo missing; fi"
53
- try:
54
- output = subprocess.check_output(
55
- cmd, shell=True, stderr=subprocess.DEVNULL, text=True
56
- ).strip()
57
- return output if output in ("file", "directory", "missing") else "unknown"
58
- except Exception:
59
- return "unknown"
60
7
 
61
8
 
62
9
 
63
10
 
64
11
  def get_find_cmd(
65
- directory: str,
66
- *,
67
- cfg: Optional["ScanConfig"] = None,
68
- *,
69
- allowed_exts: Optional[Set[str]] = False,
70
- unallowed_exts: Optional[Set[str]] = False,
71
- allowed_types: Optional[Set[str]] = False,
72
- exclude_types: Optional[Set[str]] = False,
73
- allowed_dirs: Optional[List[str]] = False,
74
- exclude_dirs: Optional[List[str]] = False,
75
- allowed_patterns: Optional[List[str]] = False,
76
- exclude_patterns: Optional[List[str]] = False,
12
+ *args,
77
13
  mindepth: Optional[int] = None,
78
14
  maxdepth: Optional[int] = None,
79
15
  depth: Optional[int] = None,
@@ -86,14 +22,23 @@ def get_find_cmd(
86
22
  **kwargs
87
23
  ) -> str:
88
24
  """
89
- Construct a Unix `find` command string from cfg and explicit keyword args.
90
-
91
- - Honors allowed/excluded patterns, dirs, and extensions from ScanConfig.
92
- - Automatically applies mindepth/maxdepth/depth/file_type filters.
25
+ Construct a Unix `find` command string that supports multiple directories.
26
+ Accepts filtering via ScanConfig-compatible kwargs.
93
27
  """
94
- cmd = [f"find {shlex.quote(directory)}"]
28
+ # Normalize inputs into canonical form
29
+ kwargs = get_safe_canonical_kwargs(*args, **kwargs)
30
+ cfg = kwargs.get('cfg') or define_defaults(**kwargs)
95
31
 
96
- # --- depth ---
32
+ # Get directory list (may come from args or kwargs)
33
+ kwargs["directories"] = ensure_directories(*args, **kwargs)
34
+ if not kwargs["directories"]:
35
+ return []
36
+
37
+ # Build base command for all directories
38
+ dir_expr = " ".join(shlex.quote(d) for d in kwargs["directories"])
39
+ cmd = [f"find {dir_expr}"]
40
+
41
+ # --- depth filters ---
97
42
  if depth is not None:
98
43
  cmd += [f"-mindepth {depth}", f"-maxdepth {depth}"]
99
44
  else:
@@ -106,7 +51,7 @@ def get_find_cmd(
106
51
  if file_type in ("f", "d"):
107
52
  cmd.append(f"-type {file_type}")
108
53
 
109
- # --- base attributes ---
54
+ # --- basic attributes ---
110
55
  if name:
111
56
  cmd.append(f"-name {shlex.quote(name)}")
112
57
  if size:
@@ -117,63 +62,53 @@ def get_find_cmd(
117
62
  cmd.append(f"-perm {shlex.quote(perm)}")
118
63
  if user:
119
64
  cmd.append(f"-user {shlex.quote(user)}")
120
- cfg = cfg or define_defaults(
121
- allowed_exts = allowed_exts,
122
- unallowed_exts = unallowed_exts,
123
- allowed_types = allowed_types,
124
- exclude_types = exclude_types,
125
- allowed_dirs = allowed_dirs,
126
- exclude_dirs = exclude_dirs,
127
- allowed_patterns = allowed_patterns,
128
- exclude_patterns = exclude_patterns,
129
- add = add
130
- )
65
+
131
66
  # --- cfg-based filters ---
132
67
  if cfg:
133
- # allowed extensions
68
+ # Allowed extensions
134
69
  if cfg.allowed_exts and cfg.allowed_exts != {"*"}:
135
70
  ext_expr = " -o ".join(
136
71
  [f"-name '*{e}'" for e in cfg.allowed_exts if e]
137
72
  )
138
73
  cmd.append(f"\\( {ext_expr} \\)")
139
74
 
140
- # disallowed extensions
141
- if cfg.unallowed_exts:
142
- for e in cfg.unallowed_exts:
75
+ # Excluded extensions
76
+ if cfg.exclude_exts:
77
+ for e in cfg.exclude_exts:
143
78
  cmd.append(f"! -name '*{e}'")
144
79
 
145
- # allowed directories (match any path)
80
+ # Allowed directories
146
81
  if cfg.allowed_dirs and cfg.allowed_dirs != ["*"]:
147
82
  dir_expr = " -o ".join(
148
83
  [f"-path '*{d}*'" for d in cfg.allowed_dirs if d]
149
84
  )
150
85
  cmd.append(f"\\( {dir_expr} \\)")
151
86
 
152
- # exclude directories
87
+ # Excluded directories
153
88
  if cfg.exclude_dirs:
154
89
  for d in cfg.exclude_dirs:
155
90
  cmd.append(f"! -path '*{d}*'")
156
91
 
157
- # allowed patterns
92
+ # Allowed patterns
158
93
  if cfg.allowed_patterns and cfg.allowed_patterns != ["*"]:
159
94
  pat_expr = " -o ".join(
160
95
  [f"-name '{p}'" for p in cfg.allowed_patterns if p]
161
96
  )
162
97
  cmd.append(f"\\( {pat_expr} \\)")
163
98
 
164
- # exclude patterns
99
+ # Excluded patterns
165
100
  if cfg.exclude_patterns:
166
101
  for p in cfg.exclude_patterns:
167
102
  cmd.append(f"! -name '{p}'")
168
103
 
169
- # allowed types
104
+ # Allowed types (semantic, not `-type`)
170
105
  if cfg.allowed_types and cfg.allowed_types != {"*"}:
171
106
  type_expr = " -o ".join(
172
107
  [f"-path '*{t}*'" for t in cfg.allowed_types if t]
173
108
  )
174
109
  cmd.append(f"\\( {type_expr} \\)")
175
110
 
176
- # excluded types
111
+ # Excluded types
177
112
  if cfg.exclude_types:
178
113
  for t in cfg.exclude_types:
179
114
  cmd.append(f"! -path '*{t}*'")
@@ -183,24 +118,12 @@ def get_find_cmd(
183
118
 
184
119
 
185
120
  def collect_globs(
186
- directory: str,
187
- cfg: Optional["ScanConfig"] = None,
188
- *,
189
- allowed_exts: Optional[Set[str]] = False,
190
- unallowed_exts: Optional[Set[str]] = False,
191
- allowed_types: Optional[Set[str]] = False,
192
- exclude_types: Optional[Set[str]] = False,
193
- allowed_dirs: Optional[List[str]] = False,
194
- exclude_dirs: Optional[List[str]] = False,
195
- allowed_patterns: Optional[List[str]] = False,
196
- exclude_patterns: Optional[List[str]] = False,
197
- patterns: Optional[List[str]] = None,
121
+ *args,
198
122
  mindepth: Optional[int] = None,
199
123
  maxdepth: Optional[int] = None,
200
124
  depth: Optional[int] = None,
201
125
  file_type: Optional[str] = None, # "f", "d", or None
202
- user_at_host: Optional[str] = None,
203
- add: bool = False,
126
+ allowed: Optional[Callable[[str], bool]] = None,
204
127
  **kwargs
205
128
  ) -> List[str] | dict:
206
129
  """
@@ -210,61 +133,58 @@ def collect_globs(
210
133
  - If file_type is "f" or "d" → returns a list of that type
211
134
  - Supports SSH mode via `user_at_host`
212
135
  """
213
- cfg = cfg or define_defaults(
214
- allowed_exts = allowed_exts,
215
- unallowed_exts = unallowed_exts,
216
- allowed_types = allowed_types,
217
- exclude_types = exclude_types,
218
- allowed_dirs = allowed_dirs,
219
- exclude_dirs = exclude_dirs,
220
- allowed_patterns = allowed_patterns,
221
- exclude_patterns = exclude_patterns,
222
- add = add
223
- )
224
- allowed = allowed or make_allowed_predicate(cfg)
225
- directory = str(directory)
226
-
227
- # Remote path (SSH)
228
- if user_at_host:
136
+ user_pass_host_key = get_user_pass_host_key(**kwargs)
137
+ kwargs["directories"] = ensure_directories(*args, **kwargs)
138
+ kwargs= get_safe_canonical_kwargs(**kwargs)
139
+ kwargs["cfg"] = kwargs.get('cfg') or define_defaults(**kwargs)
140
+
141
+ type_strs = {"f":"files","d":"dirs"}
142
+ file_type = get_proper_type_str(file_type)
143
+ file_types = make_list(file_type)
144
+ if file_type == None:
145
+ file_types = ["f","d"]
146
+ return_results = {}
147
+ return_result=[]
148
+ for file_type in file_types:
149
+ type_str = type_strs.get(file_type)
150
+ # Remote path (SSH)
229
151
  find_cmd = get_find_cmd(
230
- directory,
231
- cfg=cfg,
232
- mindepth=mindepth,
233
- maxdepth=maxdepth,
234
- depth=depth,
235
- file_type=file_type,
236
- **{k: v for k, v in kwargs.items() if v},
237
- )
238
- return run_cmd(find_cmd, user_at_host=user_at_host)
239
-
240
- # Local path (Python-native walk)
241
- root = Path(directory)
242
- results_js = {"f": [], "d": []}
243
-
244
- for p in root.rglob("*"):
245
- if p.is_file():
246
- kind = "f"
247
- elif p.is_dir():
248
- kind = "d"
249
- else:
250
- continue
251
-
252
- # If file_type is specified, skip the other kind
253
- if file_type and kind != file_type:
254
- continue
255
-
256
- if exts and kind == "f" and p.suffix.lower() not in exts:
257
- continue
258
-
259
- if patterns and not any(p.match(pat) for pat in patterns):
260
- continue
261
-
262
- results_js[kind].append(str(p))
263
-
264
- # Return based on selection
265
- if file_type is None:
266
- return results_js
267
- else:
268
- return results_js[file_type]
269
-
270
-
152
+ directories=kwargs.get("directories"),
153
+ cfg=kwargs.get('cfg'),
154
+ mindepth=mindepth,
155
+ maxdepth=maxdepth,
156
+ depth=depth,
157
+ file_type=file_type,
158
+ **user_pass_host_key,
159
+ )
160
+ result = run_pruned_func(run_cmd,find_cmd,
161
+ **kwargs
162
+
163
+ )
164
+ return_result = [res for res in result.split('\n') if res]
165
+ return_results[type_str]=return_result
166
+ if len(file_types) == 1:
167
+ return return_result
168
+ return return_results
169
+ def get_files_and_dirs(
170
+ *args,
171
+ recursive: bool = True,
172
+ include_files: bool = True,
173
+ **kwargs
174
+ ):
175
+ if recursive == False:
176
+ kwargs['maxdepth']=1
177
+ if include_files == False:
178
+ kwargs['file_type']='d'
179
+ result = collect_globs(*args,**kwargs)
180
+ if include_files == False:
181
+ return result,[]
182
+ dirs = result.get("dirs")
183
+ files = result.get("files")
184
+ return dirs,files
185
+ def collect_filepaths(
186
+ *args,
187
+ **kwargs
188
+ ) -> List[str]:
189
+ kwargs['file_type']='f'
190
+ return collect_globs(*args,**kwargs)