mirror of
https://github.com/kevinveenbirkenbach/bulk-string-replacer.git
synced 2025-09-10 12:17:14 +02:00
Compare commits
3 Commits
de4f9511d5
...
main
Author | SHA1 | Date | |
---|---|---|---|
82784bdcff | |||
40ff300a92 | |||
c54cb81812 |
119
main.py
119
main.py
@@ -2,6 +2,7 @@
|
|||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
def replace_content(path, old_string, new_string, preview, verbose):
|
def replace_content(path, old_string, new_string, preview, verbose):
|
||||||
"""
|
"""
|
||||||
Replace occurrences of old_string with new_string inside the file at path.
|
Replace occurrences of old_string with new_string inside the file at path.
|
||||||
@@ -18,22 +19,37 @@ def replace_content(path, old_string, new_string, preview, verbose):
|
|||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
print_verbose(f"Warning: Unicode decode error in file {path}. Skipping.", verbose)
|
print_verbose(f"Warning: Unicode decode error in file {path}. Skipping.", verbose)
|
||||||
|
|
||||||
|
|
||||||
def print_verbose(message, verbose):
|
def print_verbose(message, verbose):
|
||||||
if verbose:
|
if verbose:
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
def process_directory(base_path, old_string, new_string, recursive,
|
|
||||||
rename_folders, rename_files, replace_in_content,
|
def process_directory(
|
||||||
preview, verbose, include_hidden, rename_paths):
|
base_path,
|
||||||
|
old_string,
|
||||||
|
new_string,
|
||||||
|
recursive,
|
||||||
|
rename_folders,
|
||||||
|
rename_files,
|
||||||
|
replace_in_content,
|
||||||
|
preview,
|
||||||
|
verbose,
|
||||||
|
include_hidden,
|
||||||
|
rename_paths,
|
||||||
|
auto_path
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Traverse directory tree and perform operations based on flags:
|
Traverse the directory tree and perform operations based on flags:
|
||||||
- replace_in_content: replace inside file contents
|
- replace_in_content: replace inside file contents
|
||||||
- rename_files: rename files whose names contain old_string
|
- rename_files: rename files whose names contain old_string
|
||||||
- rename_folders: rename folders whose names contain old_string
|
- rename_folders: rename folders whose names contain old_string
|
||||||
- rename_paths: match old_string as a relative path and move matching items to new_string
|
- rename_paths: treat old_string as a relative path and move matching items to new_string path.
|
||||||
|
When rename_paths is set, prompts occur for Python files unless auto_path is True.
|
||||||
|
Additionally, for test_*.py files when auto_path is False, prompts to extract 'test_' prefix into a subdirectory.
|
||||||
"""
|
"""
|
||||||
# Full-path move logic
|
|
||||||
if rename_paths:
|
if rename_paths:
|
||||||
|
# Full-path moves and optional test_ prefix extraction
|
||||||
for root, dirs, files in os.walk(base_path):
|
for root, dirs, files in os.walk(base_path):
|
||||||
if not include_hidden:
|
if not include_hidden:
|
||||||
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
||||||
@@ -43,6 +59,29 @@ def process_directory(base_path, old_string, new_string, recursive,
|
|||||||
rel = os.path.relpath(full_src, base_path)
|
rel = os.path.relpath(full_src, base_path)
|
||||||
if old_string in rel:
|
if old_string in rel:
|
||||||
new_rel = rel.replace(old_string, new_string)
|
new_rel = rel.replace(old_string, new_string)
|
||||||
|
|
||||||
|
# Special handling for test_*.py when auto_path is False
|
||||||
|
if (
|
||||||
|
os.path.isfile(full_src)
|
||||||
|
and name.startswith('test_')
|
||||||
|
and name.endswith('.py')
|
||||||
|
and not auto_path
|
||||||
|
):
|
||||||
|
choice = None
|
||||||
|
while choice not in ('y', 'n'):
|
||||||
|
choice = input(
|
||||||
|
f"File {full_src} is a test module. "
|
||||||
|
"Extract 'test_' prefix into subdirectory? [y/N]: "
|
||||||
|
).strip().lower() or 'n'
|
||||||
|
if choice == 'y':
|
||||||
|
rel_dir = os.path.dirname(rel)
|
||||||
|
orig_basename = os.path.basename(rel)
|
||||||
|
base_noext = orig_basename[:-3] # remove .py
|
||||||
|
subdir_name = base_noext[len('test_'):]
|
||||||
|
new_name_part = os.path.basename(new_string)
|
||||||
|
new_filename = f"test_{new_name_part}.py"
|
||||||
|
new_rel = os.path.join(rel_dir, subdir_name, new_filename)
|
||||||
|
|
||||||
full_dst = os.path.join(base_path, new_rel)
|
full_dst = os.path.join(base_path, new_rel)
|
||||||
print_verbose(f"Moving {full_src} → {full_dst}", verbose)
|
print_verbose(f"Moving {full_src} → {full_dst}", verbose)
|
||||||
if not preview:
|
if not preview:
|
||||||
@@ -50,23 +89,72 @@ def process_directory(base_path, old_string, new_string, recursive,
|
|||||||
os.rename(full_src, full_dst)
|
os.rename(full_src, full_dst)
|
||||||
if not recursive:
|
if not recursive:
|
||||||
break
|
break
|
||||||
# Only return early when only path-mode is active
|
|
||||||
|
# Line-by-line content replacement in Python files
|
||||||
|
for root, dirs, files in os.walk(base_path):
|
||||||
|
if not include_hidden:
|
||||||
|
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
||||||
|
files = [f for f in files if not f.startswith('.')]
|
||||||
|
for f in files:
|
||||||
|
if f.endswith('.py'):
|
||||||
|
file_path = os.path.join(root, f)
|
||||||
|
print_verbose(f"Processing Python file: {file_path}", verbose)
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as ff:
|
||||||
|
lines = ff.readlines()
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print_verbose(f"Warning: Unicode decode error in file {file_path}. Skipping.", verbose)
|
||||||
|
continue
|
||||||
|
old_slash = old_string.replace('/', os.sep)
|
||||||
|
new_dot = new_string.replace('/', '.')
|
||||||
|
changed = False
|
||||||
|
for idx, line in enumerate(lines):
|
||||||
|
if old_slash in line:
|
||||||
|
start = max(0, idx - 3)
|
||||||
|
end = min(len(lines), idx + 4)
|
||||||
|
print(f"\nContext in {file_path}, line {idx+1}:")
|
||||||
|
for i in range(start, end):
|
||||||
|
prefix = '>' if i == idx else ' '
|
||||||
|
print(f"{prefix} {i+1}: {lines[i].rstrip()}")
|
||||||
|
|
||||||
|
if auto_path:
|
||||||
|
choice = '1'
|
||||||
|
else:
|
||||||
|
choice = None
|
||||||
|
while choice not in ('1', '2'):
|
||||||
|
choice = input(
|
||||||
|
f"Replace this line:\n"
|
||||||
|
f" 1) slash-based: '{old_slash}' → '{new_string}'\n"
|
||||||
|
f" 2) dot-based: '{old_slash}' → '{new_dot}'\n"
|
||||||
|
f"Choose [1/2]: "
|
||||||
|
).strip()
|
||||||
|
if choice == '1':
|
||||||
|
lines[idx] = line.replace(old_slash, new_string)
|
||||||
|
else:
|
||||||
|
lines[idx] = line.replace(old_slash, new_dot)
|
||||||
|
changed = True
|
||||||
|
print_verbose(f"Replaced line {idx+1} in {file_path}", verbose)
|
||||||
|
if changed and not preview:
|
||||||
|
with open(file_path, 'w', encoding='utf-8') as fw:
|
||||||
|
fw.writelines(lines)
|
||||||
|
if not recursive:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Exit early if only path-mode is requested
|
||||||
if not (rename_files or replace_in_content):
|
if not (rename_files or replace_in_content):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Collect folder renames to apply after traversal
|
# Fallback operations: replace content, rename files, rename folders
|
||||||
folders_to_rename = []
|
folders_to_rename = []
|
||||||
for root, dirs, files in os.walk(base_path):
|
for root, dirs, files in os.walk(base_path):
|
||||||
if not include_hidden:
|
if not include_hidden:
|
||||||
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
||||||
files = [f for f in files if not f.startswith('.')]
|
files = [f for f in files if not f.startswith('.')]
|
||||||
|
|
||||||
# Content replacement
|
|
||||||
if replace_in_content:
|
if replace_in_content:
|
||||||
for f in files:
|
for f in files:
|
||||||
replace_content(os.path.join(root, f), old_string, new_string, preview, verbose)
|
replace_content(os.path.join(root, f), old_string, new_string, preview, verbose)
|
||||||
|
|
||||||
# File renaming
|
|
||||||
if rename_files:
|
if rename_files:
|
||||||
for f in files:
|
for f in files:
|
||||||
if old_string in f:
|
if old_string in f:
|
||||||
@@ -76,7 +164,6 @@ def process_directory(base_path, old_string, new_string, recursive,
|
|||||||
if not preview:
|
if not preview:
|
||||||
os.rename(src, dst)
|
os.rename(src, dst)
|
||||||
|
|
||||||
# Gather folder renames
|
|
||||||
if rename_folders:
|
if rename_folders:
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
if old_string in d:
|
if old_string in d:
|
||||||
@@ -87,12 +174,12 @@ def process_directory(base_path, old_string, new_string, recursive,
|
|||||||
if not recursive:
|
if not recursive:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Apply folder renames
|
|
||||||
for src, dst in folders_to_rename:
|
for src, dst in folders_to_rename:
|
||||||
print_verbose(f"Renaming directory: {src} → {dst}", verbose)
|
print_verbose(f"Renaming directory: {src} → {dst}", verbose)
|
||||||
if not preview:
|
if not preview:
|
||||||
os.rename(src, dst)
|
os.rename(src, dst)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Bulk string replacer with optional full-path moves."
|
description="Bulk string replacer with optional full-path moves."
|
||||||
@@ -112,7 +199,9 @@ def main():
|
|||||||
parser.add_argument('-p', '--preview', action='store_true',
|
parser.add_argument('-p', '--preview', action='store_true',
|
||||||
help="Preview only; no changes.")
|
help="Preview only; no changes.")
|
||||||
parser.add_argument('-P', '--path', dest='rename_paths', action='store_true',
|
parser.add_argument('-P', '--path', dest='rename_paths', action='store_true',
|
||||||
help="Match old_string as relative path and move to new_string path.")
|
help="Treat old_string as path and move matching items.")
|
||||||
|
parser.add_argument('-y', '--yes', dest='auto_path', action='store_true',
|
||||||
|
help="Skip prompts and apply default replacements.")
|
||||||
parser.add_argument('-v', '--verbose', action='store_true',
|
parser.add_argument('-v', '--verbose', action='store_true',
|
||||||
help="Verbose mode.")
|
help="Verbose mode.")
|
||||||
parser.add_argument('-H', '--hidden', action='store_true',
|
parser.add_argument('-H', '--hidden', action='store_true',
|
||||||
@@ -120,7 +209,6 @@ def main():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Disallow using --path and --folders together
|
|
||||||
if args.rename_paths and args.folders:
|
if args.rename_paths and args.folders:
|
||||||
parser.error("Cannot use --path and --folders together.")
|
parser.error("Cannot use --path and --folders together.")
|
||||||
|
|
||||||
@@ -138,7 +226,8 @@ def main():
|
|||||||
preview=args.preview,
|
preview=args.preview,
|
||||||
verbose=args.verbose,
|
verbose=args.verbose,
|
||||||
include_hidden=args.hidden,
|
include_hidden=args.hidden,
|
||||||
rename_paths=args.rename_paths
|
rename_paths=args.rename_paths,
|
||||||
|
auto_path=args.auto_path
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
133
test.py
133
test.py
@@ -22,6 +22,57 @@ class TestBulkStringReplacer(unittest.TestCase):
|
|||||||
f.write(content)
|
f.write(content)
|
||||||
return full
|
return full
|
||||||
|
|
||||||
|
def test_test_prefix_extraction_prompt_no_auto(self):
|
||||||
|
# Setup a test file with test_ prefix
|
||||||
|
src = self.create_file('dir/test_module.py', 'print("hello")')
|
||||||
|
# Monkeypatch input to simulate 'y'
|
||||||
|
inputs = iter(['y'])
|
||||||
|
original_input = __builtins__['input']
|
||||||
|
__builtins__['input'] = lambda _: next(inputs)
|
||||||
|
try:
|
||||||
|
process_directory(
|
||||||
|
base_path=self.base,
|
||||||
|
old_string='module',
|
||||||
|
new_string='module_new',
|
||||||
|
recursive=True,
|
||||||
|
rename_folders=False,
|
||||||
|
rename_files=False,
|
||||||
|
replace_in_content=False,
|
||||||
|
preview=False,
|
||||||
|
verbose=False,
|
||||||
|
include_hidden=True,
|
||||||
|
rename_paths=True,
|
||||||
|
auto_path=False
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
__builtins__['input'] = original_input
|
||||||
|
|
||||||
|
# After extraction, expect dir/module/test_module_new.py
|
||||||
|
dst = os.path.join(self.base, 'dir', 'module', 'test_module_new.py')
|
||||||
|
self.assertTrue(os.path.exists(dst))
|
||||||
|
|
||||||
|
def test_test_prefix_default_no_extraction_auto(self):
|
||||||
|
# Setup a test file with test_ prefix
|
||||||
|
src = self.create_file('dir/test_file.py', 'print("hello")')
|
||||||
|
process_directory(
|
||||||
|
base_path=self.base,
|
||||||
|
old_string='file',
|
||||||
|
new_string='file_new',
|
||||||
|
recursive=True,
|
||||||
|
rename_folders=False,
|
||||||
|
rename_files=False,
|
||||||
|
replace_in_content=False,
|
||||||
|
preview=False,
|
||||||
|
verbose=False,
|
||||||
|
include_hidden=True,
|
||||||
|
rename_paths=True,
|
||||||
|
auto_path=True
|
||||||
|
)
|
||||||
|
# With auto_path, should do simple path replace: dir/test_file.py -> dir/test_file_new.py
|
||||||
|
dst = os.path.join(self.base, 'dir', 'test_file_new.py')
|
||||||
|
self.assertTrue(os.path.exists(dst))
|
||||||
|
|
||||||
|
|
||||||
def test_replace_content(self):
|
def test_replace_content(self):
|
||||||
f = self.create_file('foo.txt', 'hello OLD world')
|
f = self.create_file('foo.txt', 'hello OLD world')
|
||||||
replace_content(f, 'OLD', 'NEW', preview=False, verbose=False)
|
replace_content(f, 'OLD', 'NEW', preview=False, verbose=False)
|
||||||
@@ -37,9 +88,8 @@ class TestBulkStringReplacer(unittest.TestCase):
|
|||||||
rename_folders=False, rename_files=True,
|
rename_folders=False, rename_files=True,
|
||||||
replace_in_content=False,
|
replace_in_content=False,
|
||||||
preview=False, verbose=False,
|
preview=False, verbose=False,
|
||||||
include_hidden=True, rename_paths=False
|
include_hidden=True, rename_paths=False, auto_path=True
|
||||||
)
|
)
|
||||||
# file moved
|
|
||||||
self.assertTrue(os.path.exists(os.path.join(self.base, 'NEWfile.txt')))
|
self.assertTrue(os.path.exists(os.path.join(self.base, 'NEWfile.txt')))
|
||||||
self.assertFalse(os.path.exists(f))
|
self.assertFalse(os.path.exists(f))
|
||||||
|
|
||||||
@@ -52,16 +102,14 @@ class TestBulkStringReplacer(unittest.TestCase):
|
|||||||
rename_folders=True, rename_files=False,
|
rename_folders=True, rename_files=False,
|
||||||
replace_in_content=False,
|
replace_in_content=False,
|
||||||
preview=False, verbose=False,
|
preview=False, verbose=False,
|
||||||
include_hidden=True, rename_paths=False
|
include_hidden=True, rename_paths=False, auto_path=True
|
||||||
)
|
)
|
||||||
self.assertTrue(os.path.isdir(os.path.join(self.base, 'NEWfolder')))
|
self.assertTrue(os.path.isdir(os.path.join(self.base, 'NEWfolder')))
|
||||||
self.assertFalse(os.path.isdir(os.path.join(self.base, 'OLDfolder')))
|
self.assertFalse(os.path.isdir(os.path.join(self.base, 'OLDfolder')))
|
||||||
|
|
||||||
def test_full_path_move(self):
|
def test_full_path_move(self):
|
||||||
# prepare vars/configuration.yml
|
|
||||||
cfg = 'vars/configuration.yml'
|
cfg = 'vars/configuration.yml'
|
||||||
full = self.create_file(cfg, 'DATA')
|
full = self.create_file(cfg, 'DATA')
|
||||||
# run with -P
|
|
||||||
process_directory(
|
process_directory(
|
||||||
base_path=self.base,
|
base_path=self.base,
|
||||||
old_string='vars/configuration.yml',
|
old_string='vars/configuration.yml',
|
||||||
@@ -70,28 +118,21 @@ class TestBulkStringReplacer(unittest.TestCase):
|
|||||||
rename_folders=False, rename_files=False,
|
rename_folders=False, rename_files=False,
|
||||||
replace_in_content=False,
|
replace_in_content=False,
|
||||||
preview=False, verbose=False,
|
preview=False, verbose=False,
|
||||||
include_hidden=True, rename_paths=True
|
include_hidden=True, rename_paths=True, auto_path=True
|
||||||
)
|
)
|
||||||
# original gone, new exists
|
|
||||||
self.assertFalse(os.path.exists(full))
|
self.assertFalse(os.path.exists(full))
|
||||||
self.assertTrue(os.path.exists(os.path.join(self.base, 'config', 'main.yml')))
|
self.assertTrue(os.path.exists(os.path.join(self.base, 'config', 'main.yml')))
|
||||||
|
|
||||||
def test_path_and_folders_conflict(self):
|
def test_path_and_folders_conflict(self):
|
||||||
# simulate CLI error when combining --path and --folders
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
# replicate only the conflict check
|
|
||||||
parser.add_argument('-P', dest='rename_paths', action='store_true')
|
parser.add_argument('-P', dest='rename_paths', action='store_true')
|
||||||
parser.add_argument('-F', dest='folders', action='store_true')
|
parser.add_argument('-F', dest='folders', action='store_true')
|
||||||
args = parser.parse_args(['-P', '-F'])
|
args = parser.parse_args(['-P', '-F'])
|
||||||
# manual conflict
|
with self.assertRaises(SystemExit):
|
||||||
with self.assertRaises(SystemExit) as cm:
|
|
||||||
# mimic the parser.error behavior
|
|
||||||
if args.rename_paths and args.folders:
|
if args.rename_paths and args.folders:
|
||||||
parser.error("Cannot use --path and --folders together.")
|
parser.error("Cannot use --path and --folders together.")
|
||||||
self.assertNotEqual(cm.exception.code, 0)
|
|
||||||
|
|
||||||
def test_preview_does_nothing(self):
|
def test_preview_does_nothing(self):
|
||||||
# create file and folder matching
|
|
||||||
f = self.create_file('OLD.txt', 'OLD')
|
f = self.create_file('OLD.txt', 'OLD')
|
||||||
os.makedirs(os.path.join(self.base, 'OLDdir'))
|
os.makedirs(os.path.join(self.base, 'OLDdir'))
|
||||||
process_directory(
|
process_directory(
|
||||||
@@ -101,13 +142,71 @@ class TestBulkStringReplacer(unittest.TestCase):
|
|||||||
rename_folders=True, rename_files=True,
|
rename_folders=True, rename_files=True,
|
||||||
replace_in_content=True,
|
replace_in_content=True,
|
||||||
preview=True, verbose=False,
|
preview=True, verbose=False,
|
||||||
include_hidden=True, rename_paths=True
|
include_hidden=True, rename_paths=True, auto_path=True
|
||||||
)
|
)
|
||||||
# nothing changed
|
|
||||||
self.assertTrue(os.path.exists(f))
|
self.assertTrue(os.path.exists(f))
|
||||||
self.assertTrue(os.path.isdir(os.path.join(self.base, 'OLDdir')))
|
self.assertTrue(os.path.isdir(os.path.join(self.base, 'OLDdir')))
|
||||||
with open(f, 'r', encoding='utf-8') as fp:
|
with open(f, 'r', encoding='utf-8') as fp:
|
||||||
self.assertIn('OLD', fp.read())
|
self.assertIn('OLD', fp.read())
|
||||||
|
|
||||||
|
def test_module_path_replacement_in_python_files(self):
|
||||||
|
content = 'from old/path import func'
|
||||||
|
src = self.create_file('old/path/module.py', content)
|
||||||
|
process_directory(
|
||||||
|
base_path=self.base,
|
||||||
|
old_string='old/path', new_string='old.path',
|
||||||
|
recursive=True,
|
||||||
|
rename_folders=False, rename_files=False,
|
||||||
|
replace_in_content=False,
|
||||||
|
preview=False, verbose=False,
|
||||||
|
include_hidden=True, rename_paths=True, auto_path=True
|
||||||
|
)
|
||||||
|
new_path = os.path.join(self.base, 'old.path', 'module.py')
|
||||||
|
self.assertTrue(os.path.exists(new_path))
|
||||||
|
with open(new_path, 'r', encoding='utf-8') as fp:
|
||||||
|
self.assertIn('from old.path import func', fp.read())
|
||||||
|
|
||||||
|
def test_non_python_files_are_not_content_updated(self):
|
||||||
|
content = 'some reference to old/path in text'
|
||||||
|
txt = self.create_file('old/path/readme.txt', content)
|
||||||
|
process_directory(
|
||||||
|
base_path=self.base,
|
||||||
|
old_string='old/path', new_string='old.path',
|
||||||
|
recursive=True,
|
||||||
|
rename_folders=False, rename_files=False,
|
||||||
|
replace_in_content=False,
|
||||||
|
preview=False, verbose=False,
|
||||||
|
include_hidden=True, rename_paths=True, auto_path=True
|
||||||
|
)
|
||||||
|
new_txt = os.path.join(self.base, 'old.path', 'readme.txt')
|
||||||
|
self.assertTrue(os.path.exists(new_txt))
|
||||||
|
with open(new_txt, 'r', encoding='utf-8') as fp:
|
||||||
|
self.assertIn('old/path', fp.read())
|
||||||
|
|
||||||
|
def test_auto_path_line_level_replacement(self):
|
||||||
|
# create a Python file with two occurrences
|
||||||
|
lines = [
|
||||||
|
'import a\n',
|
||||||
|
'path = "old/path/to/module"\n',
|
||||||
|
'print("old/path/example")\n'
|
||||||
|
]
|
||||||
|
py = self.create_file('old/path/test.py', ''.join(lines))
|
||||||
|
process_directory(
|
||||||
|
base_path=self.base,
|
||||||
|
old_string='old/path', new_string='new/path',
|
||||||
|
recursive=True,
|
||||||
|
rename_folders=False, rename_files=False,
|
||||||
|
replace_in_content=False,
|
||||||
|
preview=False, verbose=False,
|
||||||
|
include_hidden=True, rename_paths=True, auto_path=True
|
||||||
|
)
|
||||||
|
new_py = os.path.join(self.base, 'new', 'path', 'test.py')
|
||||||
|
self.assertTrue(os.path.exists(new_py))
|
||||||
|
with open(new_py, 'r', encoding='utf-8') as fp:
|
||||||
|
content = fp.read()
|
||||||
|
# all replaced slash-based
|
||||||
|
self.assertIn('path = "new/path/to/module"', content)
|
||||||
|
self.assertIn('print("new/path/example")', content)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
Reference in New Issue
Block a user