Created
December 8, 2021 14:12
-
-
Save jupiterbjy/2fde6aa36672ad2ecb21485bbdb3b9b4 to your computer and use it in GitHub Desktop.
Search function for searching or replacing files that have the search keyword recursively. Made this to help myself change asyncio project into anyio. Pretty sure this is reinvention of wheel but whatever!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Test use-case | |
>>> len(list(file_search_gen("./", "asyncio", file_extensions=(".py",)))) | |
6 | |
>>> for f in file_search_gen("./", "asyncio", "REPLACE_THIS", file_extensions=(".py",)): | |
... print(f.as_posix()) | |
... | |
telethon_examples/interactive_telegram_client.py | |
telethon_examples/payment.py | |
telethon_examples/quart_login.py | |
tests/telethon/client/test_messages.py | |
tests/telethon/events/test_chataction.py | |
tests/telethon/test_helpers.py | |
""" | |
def file_search_gen( | |
path, | |
str_to_find: str, | |
replace="", | |
whitelist_mode=True, | |
file_extensions=(), | |
fallback_encodings=(), | |
print_error=True, | |
exclude_directory=(".venv", "venv"), | |
): | |
""" | |
generator I use to find texts in nested python libraries. | |
Args: | |
path: string or pathlib.Path, folder to start search. | |
str_to_find: string to find. | |
replace: if not empty, all found strings will be replaced. | |
whitelist_mode: if True, file_extensions will act as whitelist | |
file_extensions: File extension to search/ignore for. Will act as blacklist if whitelist_mode is False. | |
fallback_encodings: encodings to use when utf8 and system default fails. | |
print_error: If True, prints decode error. | |
exclude_directory: folders to exclude | |
""" | |
import pathlib | |
from typing import Generator | |
from sys import getdefaultencoding | |
path = pathlib.Path(path) | |
file_extensions = set(file_extensions) | |
fallback_encodings = ["utf8", getdefaultencoding()] + list(fallback_encodings) | |
encodings = set(fallback_encodings) | |
excluding_paths = tuple(map(pathlib.Path, exclude_directory)) | |
print_func = print if print_error else lambda x: None | |
def _replace(file_: pathlib.Path, src: str, encoding_: str): | |
replaced = src.replace(str_to_find, replace) | |
file_.write_text(replaced, encoding=encoding_) | |
replace_func = _replace if replace else lambda x, y, z: None | |
def filtered_path_gen( | |
directory: pathlib.Path, | |
) -> Generator[pathlib.Path, None, None]: | |
for path_ in directory.iterdir(): | |
if path_.is_dir(): | |
if path_ in excluding_paths: | |
continue | |
yield from filtered_path_gen(path_) | |
elif whitelist_mode * (path_.suffix in file_extensions): | |
yield path_ | |
for file in filtered_path_gen(path): | |
for encoding in encodings: | |
try: | |
data = file.read_text(encoding=encoding) | |
except UnicodeDecodeError: | |
continue | |
success_encoding = encoding | |
break | |
else: | |
# runs when no break is called | |
print_func(f"No matching encoding for file '{file.as_posix()}'") | |
continue | |
if str_to_find in data: | |
replace_func(file, data, success_encoding) | |
yield file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment