Skip to content

Instantly share code, notes, and snippets.

@jupiterbjy
Created December 8, 2021 14:12
Show Gist options
  • Save jupiterbjy/2fde6aa36672ad2ecb21485bbdb3b9b4 to your computer and use it in GitHub Desktop.
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!
"""
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