Skip to content
This repository was archived by the owner on Mar 13, 2024. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 70 additions & 7 deletions src/python3_pip_skeleton/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pathlib import Path
from subprocess import STDOUT, CalledProcessError, call, check_output
from tempfile import TemporaryDirectory
from typing import List
from typing import Callable, Dict, List, Tuple

import tomli

Expand All @@ -20,12 +20,18 @@
MERGE_BRANCH = "skeleton-merge-branch"
# Extensions to change
CHANGE_SUFFIXES = [".py", ".rst", ".cfg", "", ".toml"]
# Files not to change
IGNORE_FILES = [
"test_boilerplate_removed.py",
"pin-requirements.rst",
"update-tools.rst",
]
# Files not to change where IGNORE_FILES[x] is a list of tuples where substitutions
# will be ignored in that file in any substring between the two strings.
# An empty list will ignore the whole file.
IGNORE_FILES: Dict[str, List[Tuple[str, str]]] = {
"update-tools.rst": [],
"test_boilerplate_removed.py": [],
"pin-requirements.rst": [],
"0002-switched-to-pip-skeleton.rst:": [],
"README.rst": [
("adopt this skeleton project see", "that describes what your module does")
],
}

SKELETON_ROOT_COMMIT = "ededf00035e6ccfac78946213009c1ecd7c110a9"

Expand Down Expand Up @@ -54,6 +60,48 @@ def __truediv__(self, other) -> Path:
return Path(self.name) / other


def find_ignore_sections(
file_name: str, file_text: str, ignore_sections: List[Tuple[str, str]]
) -> List[re.Match]:
ignore_section_matches = []
for sub_strings in ignore_sections:
pre_sub_string, post_sub_string = sub_strings
regex = rf"(?s){pre_sub_string}(.*?){post_sub_string}"
# finditer so we can throw an error if the used ignore strings ignore
# more than once in the file
original_substrings = list(re.finditer(regex, file_text))
assert original_substrings, (
f"could not find substrings {pre_sub_string} or "
f"{post_sub_string} in {file_name}."
)
assert len(original_substrings) == 1, (
f"multiple substrings found between {pre_sub_string} and "
f"{post_sub_string} in {file_name}."
)
ignore_section_matches.append(original_substrings[0])

ignore_section_matches.sort(key=lambda x: x.start())
return ignore_section_matches


def replace_text_ignoring_sections(
text: str,
ignore_section_matches: List[re.Match],
text_replacement_method: Callable,
) -> str:
replacement_text = ""
next_start = 0
for ignore_section in ignore_section_matches:
replacement_text += text_replacement_method(
text[next_start : ignore_section.start()]
)
replacement_text += text[ignore_section.start() : ignore_section.end()]
next_start = ignore_section.end()

replacement_text += text_replacement_method(text[next_start : len(text)])
return replacement_text


def merge_skeleton(
path: Path,
org: str,
Expand Down Expand Up @@ -106,6 +154,21 @@ def replace_in_file(file_path: Path, text_from: str, text_to: str):
if child.suffix in CHANGE_SUFFIXES and child.name not in IGNORE_FILES:
text = replace_text(child.read_text())
child.write_text(text)
# Replace the file, ignoring text between specified substrings
elif (
child.suffix in CHANGE_SUFFIXES
and child.name in IGNORE_FILES
and IGNORE_FILES[child.name]
):
original_text = child.read_text()
ignore_sections = find_ignore_sections(
child.name, original_text, IGNORE_FILES[child.name]
)
child.write_text(
replace_text_ignoring_sections(
original_text, ignore_sections, replace_text
)
)

# Change instructions in the docs to reflect which pip skeleton is in use
replace_in_file(
Expand Down