abstract-search 0.0.0.1__tar.gz

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.
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: abstract_search
3
+ Version: 0.0.0.1
4
+ Summary: Standalone string search across files and directories with allow/exclude filtering; stdlib-only core that reads code, text, pdf, office, and archive-based formats.
5
+ Author-email: putkoff <partners@abstractendeavors.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/AbstractEndeavors/abstract_search
8
+ Keywords: search,grep,files,filters,text-extraction,dependency-free
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ Requires-Python: >=3.8
16
+ Description-Content-Type: text/markdown
17
+ Provides-Extra: pdf
18
+ Requires-Dist: pdfplumber; extra == "pdf"
19
+ Provides-Extra: ocr
20
+ Requires-Dist: pytesseract; extra == "ocr"
21
+ Requires-Dist: pdf2image; extra == "ocr"
22
+ Provides-Extra: xls
23
+ Requires-Dist: xlrd; extra == "xls"
24
+ Provides-Extra: xlsb
25
+ Requires-Dist: pyxlsb; extra == "xlsb"
26
+ Provides-Extra: dbf
27
+ Requires-Dist: dbfread; extra == "dbf"
28
+ Provides-Extra: parquet
29
+ Requires-Dist: pyarrow; extra == "parquet"
30
+ Provides-Extra: all
31
+ Requires-Dist: pdfplumber; extra == "all"
32
+ Requires-Dist: pytesseract; extra == "all"
33
+ Requires-Dist: pdf2image; extra == "all"
34
+ Requires-Dist: xlrd; extra == "all"
35
+ Requires-Dist: pyxlsb; extra == "all"
36
+ Requires-Dist: dbfread; extra == "all"
37
+ Requires-Dist: pyarrow; extra == "all"
38
+
39
+ # abstract_search
40
+
41
+ Standalone string search across files and directories with allow/exclude
42
+ filtering. Stdlib-only at import time — pdf, office, and spreadsheet readers
43
+ load lazily and are optional extras.
44
+
45
+ ```python
46
+ from abstract_search import findContent
47
+
48
+ # search every readable file under a directory
49
+ hits = findContent("/path/to/project", strings=["needle"], get_lines=True)
50
+
51
+ # narrow by extension, merge extra excludes with the defaults
52
+ hits = findContent("/path/to/project", strings=["needle"],
53
+ allowed_exts="py", exclude_dirs="tests", add=True)
54
+
55
+ # exact multi-line match locations
56
+ locs = findContent("/path/to/project", strings=["def main(", "return"],
57
+ structured=True)
58
+ ```
59
+
60
+ Filter semantics: passing a filter kwarg **replaces** its default set;
61
+ `add=True` **merges** with the defaults instead. Defaults skip
62
+ `node_modules`, `__pycache__`, backups, media/binary extensions, and
63
+ `__init__*` files (see `constants.py`).
64
+
65
+ ```python
66
+ from abstract_search import make_allowed_predicate, filter_allowed_items, search_files
67
+
68
+ allowed = make_allowed_predicate(exclude_exts=".log", add=True)
69
+ kept = filter_allowed_items(paths, allowed_exts=[".py", ".md"])
70
+ hits = search_files("needle", "/path/to/project") # line-level SearchHit records
71
+ ```
72
+
73
+ Optional readers: `pip install abstract_search[pdf]` (pdfplumber),
74
+ `[ocr]`, `[xls]`, `[xlsb]`, `[dbf]`, `[parquet]`, or `[all]`.
@@ -0,0 +1,36 @@
1
+ # abstract_search
2
+
3
+ Standalone string search across files and directories with allow/exclude
4
+ filtering. Stdlib-only at import time — pdf, office, and spreadsheet readers
5
+ load lazily and are optional extras.
6
+
7
+ ```python
8
+ from abstract_search import findContent
9
+
10
+ # search every readable file under a directory
11
+ hits = findContent("/path/to/project", strings=["needle"], get_lines=True)
12
+
13
+ # narrow by extension, merge extra excludes with the defaults
14
+ hits = findContent("/path/to/project", strings=["needle"],
15
+ allowed_exts="py", exclude_dirs="tests", add=True)
16
+
17
+ # exact multi-line match locations
18
+ locs = findContent("/path/to/project", strings=["def main(", "return"],
19
+ structured=True)
20
+ ```
21
+
22
+ Filter semantics: passing a filter kwarg **replaces** its default set;
23
+ `add=True` **merges** with the defaults instead. Defaults skip
24
+ `node_modules`, `__pycache__`, backups, media/binary extensions, and
25
+ `__init__*` files (see `constants.py`).
26
+
27
+ ```python
28
+ from abstract_search import make_allowed_predicate, filter_allowed_items, search_files
29
+
30
+ allowed = make_allowed_predicate(exclude_exts=".log", add=True)
31
+ kept = filter_allowed_items(paths, allowed_exts=[".py", ".md"])
32
+ hits = search_files("needle", "/path/to/project") # line-level SearchHit records
33
+ ```
34
+
35
+ Optional readers: `pip install abstract_search[pdf]` (pdfplumber),
36
+ `[ocr]`, `[xls]`, `[xlsb]`, `[dbf]`, `[parquet]`, or `[all]`.
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "abstract_search"
7
+ version = "0.0.0.01"
8
+ description = "Standalone string search across files and directories with allow/exclude filtering; stdlib-only core that reads code, text, pdf, office, and archive-based formats."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ authors = [{ name = "putkoff", email = "partners@abstractendeavors.com" }]
12
+ license = { text = "MIT" }
13
+ keywords = ["search", "grep", "files", "filters", "text-extraction", "dependency-free"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Operating System :: OS Independent",
20
+ "Topic :: Software Development :: Libraries",
21
+ ]
22
+ # Intentionally EMPTY — this package's whole reason for existing is to have no deps.
23
+ dependencies = []
24
+
25
+ # Heavy readers are lazy-loaded per file type; install only what you need.
26
+ [project.optional-dependencies]
27
+ pdf = ["pdfplumber"]
28
+ ocr = ["pytesseract", "pdf2image"]
29
+ xls = ["xlrd"]
30
+ xlsb = ["pyxlsb"]
31
+ dbf = ["dbfread"]
32
+ parquet = ["pyarrow"]
33
+ all = ["pdfplumber", "pytesseract", "pdf2image", "xlrd", "pyxlsb", "dbfread", "pyarrow"]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/AbstractEndeavors/abstract_search"
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,57 @@
1
+ # Standalone string-search + search-filter package. Stdlib-only at import
2
+ # time; heavy readers (pdfplumber, xlrd, ...) load lazily per file type.
3
+ from .constants import (
4
+ MEDIA_TYPES,
5
+ get_media_map,
6
+ get_media_exts,
7
+ derive_media_type,
8
+ DEFAULT_ALLOWED_EXTS,
9
+ DEFAULT_EXCLUDE_EXTS,
10
+ DEFAULT_EXCLUDE_TYPES,
11
+ DEFAULT_EXCLUDE_DIRS,
12
+ DEFAULT_EXCLUDE_PATTERNS,
13
+ CANONICAL_MAP,
14
+ )
15
+ from .filters import (
16
+ ScanConfig,
17
+ make_list,
18
+ make_allowed_predicate,
19
+ get_allowed_predicate,
20
+ filter_allowed_items,
21
+ define_defaults,
22
+ ensure_directories,
23
+ get_file_filters,
24
+ get_files_and_dirs,
25
+ get_globs,
26
+ get_allowed_files,
27
+ get_allowed_dirs,
28
+ get_all_allowed_files,
29
+ get_all_allowed_dirs,
30
+ get_safe_kwargs,
31
+ get_safe_canonical_kwargs,
32
+ get_file_filter_kwargs,
33
+ )
34
+ from .reader import (
35
+ ExtractedText,
36
+ SearchHit,
37
+ WalkConfig,
38
+ DEFAULT_WALK,
39
+ extract_text,
40
+ iter_files,
41
+ read_paths,
42
+ search_files,
43
+ read_any_file,
44
+ read_file_as_text,
45
+ read_directory,
46
+ read_directory_many,
47
+ read_files,
48
+ )
49
+ from .find_content import (
50
+ findContent,
51
+ findContentAndEdit,
52
+ getPaths,
53
+ find_lines,
54
+ stringInContent,
55
+ request_find_console_stop,
56
+ reset_find_console_stop,
57
+ )
@@ -0,0 +1,156 @@
1
+ # constants.py — media-type data, default allow/exclude sets, and the
2
+ # canonical-kwargs alias map used to normalize caller keyword arguments.
3
+ import re
4
+ from typing import Callable, List, Optional, Set, Dict
5
+
6
+ # -------------------------
7
+ # Media types
8
+ # -------------------------
9
+ # Category -> set of extensions.
10
+ MEDIA_TYPES: Dict[str, Set[str]] = {
11
+ "archive": {".7z", ".bz2", ".dmg", ".egg", ".gz", ".iso", ".jar", ".rar",
12
+ ".tar", ".tgz", ".war", ".whl", ".xz", ".zip", ".zpaq"},
13
+ "audio": {".aac", ".aif", ".aiff", ".amr", ".flac", ".m4a", ".mid", ".midi",
14
+ ".mka", ".mp3", ".ogg", ".opus", ".wav", ".wma"},
15
+ "code": {".bash", ".c", ".cjs", ".coffee", ".cpp", ".css", ".dockerfile",
16
+ ".go", ".gql", ".graphql", ".h", ".hpp", ".htm", ".html", ".java",
17
+ ".js", ".jsx", ".kt", ".less", ".lua", ".makefile", ".mjs", ".php",
18
+ ".ps1", ".py", ".rb", ".rs", ".sass", ".scss", ".sh", ".sol",
19
+ ".sql", ".svelte", ".swift", ".ts", ".tsx", ".vue", ".yml"},
20
+ "data_science": {".avro", ".db", ".h5", ".hdf5", ".ipynb", ".npy", ".npz",
21
+ ".parquet", ".pickle", ".sqlite"},
22
+ "document": {".azw", ".cfg", ".csv", ".doc", ".docx", ".epub", ".ini",
23
+ ".json", ".key", ".log", ".markdown", ".md", ".mobi",
24
+ ".numbers", ".odt", ".pages", ".pdf", ".rtf", ".tex", ".toml",
25
+ ".tsv", ".txt", ".xml", ".yaml", ".yml"},
26
+ "executable": {".apk", ".app", ".bin", ".deb", ".dll", ".exe", ".ipa", ".rpm"},
27
+ "font": {".eot", ".otf", ".ttf", ".woff", ".woff2"},
28
+ "geospatial": {".dbf", ".geojson", ".gpkg", ".gpx", ".kml", ".kmz", ".osm",
29
+ ".shp", ".shx", ".tif", ".tiff", ".wkt"},
30
+ "image": {".ai", ".apng", ".bmp", ".eps", ".gif", ".heic", ".heif", ".ico",
31
+ ".jp2", ".jpeg", ".jpg", ".jxl", ".png", ".psd", ".raw", ".svg",
32
+ ".tiff", ".webp"},
33
+ "pandas_data": {".dta", ".feather", ".h5", ".hdf", ".msgpack", ".orc",
34
+ ".parquet", ".pickle", ".pkl", ".sas7bdat", ".sav", ".stata"},
35
+ "presentation": {".odp", ".ppt", ".pptx"},
36
+ "spreadsheet": {".csv", ".ods", ".tsv", ".xls", ".xlsx"},
37
+ "three_d": {".blend", ".fbx", ".glb", ".gltf", ".obj", ".stl", ".usd", ".usdz"},
38
+ "video": {".3gp", ".asf", ".avi", ".f4v", ".flv", ".m2ts", ".m4v", ".mkv",
39
+ ".mov", ".mp4", ".mpeg", ".mpg", ".mts", ".ogg", ".vob", ".webm",
40
+ ".wmv"},
41
+ }
42
+
43
+ def get_media_map(categories=None):
44
+ """
45
+ Return a sub-dict of MEDIA_TYPES for the given categories.
46
+ If categories is None or empty, return the whole MEDIA_TYPES.
47
+ """
48
+ if not categories:
49
+ return MEDIA_TYPES
50
+ cats = {str(c) for c in categories}
51
+ return {c: MEDIA_TYPES[c] for c in cats if c in MEDIA_TYPES}
52
+
53
+ def get_media_exts(categories=None):
54
+ """
55
+ Return a flat, sorted list of all extensions for the given categories.
56
+ """
57
+ media_map = get_media_map(categories)
58
+ return sorted({ext for exts in media_map.values() for ext in exts})
59
+
60
+ def derive_media_type(obj):
61
+ ext = None
62
+ if obj:
63
+ import os
64
+ ext = os.path.splitext(str(obj))[-1] or str(obj)
65
+ if ext:
66
+ for typ, exts in MEDIA_TYPES.items():
67
+ if ext in exts:
68
+ return typ
69
+
70
+ # -------------------------
71
+ # Default sets
72
+ # -------------------------
73
+ DEFAULT_ALLOWED_EXTS: Set[str] = {
74
+ ".py", ".pyw", # python
75
+ ".js", ".jsx", ".ts", ".tsx", ".mjs", # JS/TS
76
+ ".html", ".htm", ".xml", # markup
77
+ ".css", ".scss", ".sass", ".less", # styles
78
+ ".json", ".yaml", ".yml", ".toml", ".ini", # configs
79
+ ".cfg", ".md", ".markdown", ".rst", # docs
80
+ ".sh", ".bash", ".env", # scripts/env
81
+ ".txt" # plain text
82
+ }
83
+
84
+ DEFAULT_EXCLUDE_TYPES: Set[str] = {
85
+ "image", "video", "audio", "presentation",
86
+ "spreadsheet", "archive", "executable"
87
+ }
88
+
89
+ # never want these—even if they sneak into ALLOWED
90
+ _unallowed = set(get_media_exts(DEFAULT_EXCLUDE_TYPES)) | {
91
+ ".bak", ".shp", ".cpg", ".dbf", ".shx", ".geojson",
92
+ ".pyc", ".prj", ".sbn", ".sbx"
93
+ }
94
+ DEFAULT_EXCLUDE_EXTS: Set[str] = {e for e in _unallowed if e not in DEFAULT_ALLOWED_EXTS}
95
+
96
+ DEFAULT_EXCLUDE_DIRS: Set[str] = {
97
+ "node_modules", "old", "__pycache__", "backups", "backup",
98
+ "backs", "trash", "depriciated", "__init__"
99
+ }
100
+
101
+ DEFAULT_EXCLUDE_PATTERNS: Set[str] = {
102
+ "__init__*", "*.tmp", "*.log", "*.lock", "*.zip", "*~"
103
+ }
104
+ DEFAULT_EXCLUDE_FILE_PATTERNS = DEFAULT_EXCLUDE_PATTERNS
105
+ DEFAULT_ALLOWED_PATTERNS: List[str] = ["*"]
106
+ DEFAULT_ALLOWED_DIRS: List[str] = ["*"]
107
+ DEFAULT_ALLOWED_TYPES: List[str] = ["*"]
108
+
109
+ AllowedPredicate = Optional[Callable[[str], bool]]
110
+
111
+ # -------------------------
112
+ # Canonical kwargs aliases
113
+ # -------------------------
114
+ CANONICAL_MAP = {
115
+ "directories": ["directory", "directories", "dir", "dirs", "d", "dirname", "paths", "path", "roots", "root"],
116
+ "files": ["file", "filepath", "file_path", "files", "filepaths", "file_paths", "paths", "path", "f"],
117
+ "allowed_exts": ["allow_ext", "allowed_ext", "include_ext", "include_exts", "exts_allowed"],
118
+ "exclude_exts": ["exclude_ext", "excluded_ext", "excluded_exts", "unallowed_ext", "unallowed_exts"],
119
+ "allowed_types": ["allow_type", "allowed_type", "include_type", "include_types", "types_allowed"],
120
+ "exclude_types": ["exclude_type", "excluded_type", "excluded_types", "unallowed_type", "unallowed_types"],
121
+ "allowed_dirs": ["allow_dir", "allowed_dir", "include_dir", "include_dirs", "dirs_allowed"],
122
+ "exclude_dirs": ["exclude_dir", "excluded_dir", "excluded_dirs", "unallowed_dir", "unallowed_dirs"],
123
+ "allowed_patterns": ["allow_pattern", "allowed_pattern", "include_pattern", "include_patterns", "patterns_allowed"],
124
+ "exclude_patterns": ["exclude_pattern", "excluded_pattern", "excluded_patterns", "unallowed_pattern", "unallowed_patterns"],
125
+ "add": ["add"],
126
+ "cfg": ["cfg"],
127
+ "recursive": ["recursive"],
128
+ "strings": ["strings"],
129
+ "total_strings": ["total_strings"],
130
+ "parse_lines": ["parse_lines"],
131
+ "spec_line": ["spec_line"],
132
+ "get_lines": ["get_lines"],
133
+ }
134
+ DEFAULT_ALLOWED_EXCLUDE_MAP = {
135
+ "allowed_exts": {"default": DEFAULT_ALLOWED_EXTS, "type": type(DEFAULT_ALLOWED_EXTS), "canonical": CANONICAL_MAP.get("allowed_exts")},
136
+ "exclude_exts": {"default": DEFAULT_EXCLUDE_EXTS, "type": type(DEFAULT_EXCLUDE_EXTS), "canonical": CANONICAL_MAP.get("exclude_exts")},
137
+ "allowed_types": {"default": DEFAULT_ALLOWED_TYPES, "type": type(DEFAULT_ALLOWED_TYPES), "canonical": CANONICAL_MAP.get("allowed_types")},
138
+ "exclude_types": {"default": DEFAULT_EXCLUDE_TYPES, "type": type(DEFAULT_EXCLUDE_TYPES), "canonical": CANONICAL_MAP.get("exclude_types")},
139
+ "allowed_dirs": {"default": DEFAULT_ALLOWED_DIRS, "type": type(DEFAULT_ALLOWED_DIRS), "canonical": CANONICAL_MAP.get("allowed_dirs")},
140
+ "exclude_dirs": {"default": DEFAULT_EXCLUDE_DIRS, "type": type(DEFAULT_EXCLUDE_DIRS), "canonical": CANONICAL_MAP.get("exclude_dirs")},
141
+ "allowed_patterns": {"default": DEFAULT_ALLOWED_PATTERNS, "type": type(DEFAULT_ALLOWED_PATTERNS), "canonical": CANONICAL_MAP.get("allowed_patterns")},
142
+ "exclude_patterns": {"default": DEFAULT_EXCLUDE_PATTERNS, "type": type(DEFAULT_EXCLUDE_PATTERNS), "canonical": CANONICAL_MAP.get("exclude_patterns")},
143
+ }
144
+ DEFAULT_CANONICAL_MAP = {
145
+ "directories": {"default": [], "type": list, "canonical": CANONICAL_MAP.get("directories")},
146
+ "files": {"default": [], "type": list, "canonical": CANONICAL_MAP.get("files")},
147
+ **DEFAULT_ALLOWED_EXCLUDE_MAP,
148
+ "allowed": {"default": None, "type": bool, "canonical": CANONICAL_MAP.get("allowed")},
149
+ "add": {"default": False, "type": bool, "canonical": CANONICAL_MAP.get("add")},
150
+ "recursive": {"default": True, "type": bool, "canonical": CANONICAL_MAP.get("recursive")},
151
+ "strings": {"default": None, "type": list, "canonical": CANONICAL_MAP.get("strings")},
152
+ "total_strings": {"default": False, "type": bool, "canonical": CANONICAL_MAP.get("total_strings")},
153
+ "parse_lines": {"default": False, "type": bool, "canonical": CANONICAL_MAP.get("parse_lines")},
154
+ "spec_line": {"default": False, "type": bool, "canonical": CANONICAL_MAP.get("spec_line")},
155
+ "get_lines": {"default": False, "type": bool, "canonical": CANONICAL_MAP.get("get_lines")},
156
+ }