Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "ti-84-python"
version = "1.69.0"
version = "1.70.0"
description = "TI-84 Plus CE-T Python Edition Applications"
readme = "README.md"
requires-python = ">=3.13"
Expand Down
144 changes: 134 additions & 10 deletions src/support/minimiser.conf
Original file line number Diff line number Diff line change
@@ -1,18 +1,142 @@
{
"default": {
"aggressive": false,
"preserve": []
},
"exclude": {
"files": [
"__init__.py",
"turtle.py"
],
"folders": [
"support",
"ti_desktop"
],
"files": [
"__init__.py",
"turtle.py"
]
},
"aggressive": [
"resident.py"
],
"preserve": [
"run"
]
"folders": {
"examples": {
"aggressive": true,
"preserve": []
},
"ui": {
"aggressive": true,
"preserve": []
}
},
"files": {
"barometr.py": {
"aggressive": true,
"preserve": [
"PASCAL",
"HECTOPASCAL",
"MMHG",
"convert",
"calculate_p0_from_p",
"calculate_p_from_p0"
]
},
"batphase.py": {
"aggressive": true,
"preserve": [
"classify_sequence",
"detect_feeding_buzz_phases"
]
},
"batpulse.py": {
"aggressive": true,
"preserve": [
"chart_pulse_timings"
]
},
"dateutl.py": {
"aggressive": true,
"preserve": [
"seconds_since_epoch",
"timestamp_to_date",
"is_leap_year",
"prompt_for_date"
]
},
"iptutils.py": {
"aggressive": true,
"preserve": [
"prompt_for_integer",
"prompt_for_option",
"prompt_for_option_with_values",
"prompt_for_float",
"prompt_for_yes_no"
]
},
"julian.py": {
"aggressive": true,
"preserve": [
"julian_date"
]
},
"odelib.py": {
"aggressive": true,
"preserve": [
"EULER",
"PREDICTOR_CORRECTOR",
"RUNGE_KUTTA_4",
"OUTPUT_TEXT",
"OUTPUT_CHART",
"OUTPUT_SILENT",
"solve"
]
},
"oututils.py": {
"aggressive": true,
"preserve": [
"print_title",
"print_list"
]
},
"keycodes.py": {
"aggressive": true,
"preserve": []
},
"resident.py": {
"aggressive": true,
"preserve": [
"run"
]
},
"seasonal.py": {
"aggressive": true,
"preserve": [
"run"
]
},
"strutils.py": {
"aggressive": true,
"preserve": [
"pad_string",
"truncate_string"
]
},
"tabulate.py": {
"aggressive": true,
"preserve": [
"build_table",
"print_table"
]
},
"tempconv.py": {
"aggressive": true,
"preserve": [
"CENTIGRADE",
"FAHRENHEIT",
"KELVIN",
"DECIMAL_PLACES",
"convert"
]
},
"winter.py": {
"aggressive": true,
"preserve": [
"run"
]
}
}
}
66 changes: 53 additions & 13 deletions src/support/minimiser.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
PROJECT_FOLDER = Path(__file__).parent.parent.parent


def prepare_output_folder():
def prepare_output_folder() -> str:
"""
Make sure the output folder exists and is empty

Expand All @@ -69,7 +69,7 @@ def prepare_output_folder():
return output_folder


def remove_comments(lines):
def remove_comments(lines: list[str]) -> list[str]:
"""
Give the content of a source file as a list of individual lines, remove docstrings and comments

Expand Down Expand Up @@ -100,7 +100,7 @@ def remove_comments(lines):
return lines


def print_message(message):
def print_message(message: str) -> None:
"""
Show a timestamped message

Expand All @@ -110,7 +110,12 @@ def print_message(message):
print(f"{timestamp} : {message}")


def minify_file(file_path, aggressive, preserve_globals, output_folder):
def minify_file(
file_path: Path,
aggressive: bool,
preserve: list[str],
output_folder: str
) -> None:
"""
Minify a Python source file

Expand All @@ -132,23 +137,58 @@ def minify_file(file_path, aggressive, preserve_globals, output_folder):
source = "".join(lines)
minified = minify(source,
file_path,
remove_pass=False,
remove_pass=True,
remove_literal_statements=True,
rename_locals=True,
rename_globals=aggressive,
preserve_globals=preserve_globals)
preserve_globals=preserve,
remove_asserts=True,
remove_debug=True,
prefer_single_line=True)

# Write the "minimised" file
output_file_path = output_folder / Path(file_path).name
with open(output_file_path, mode="wt", encoding="UTF-8") as out_handle:
out_handle.writelines(minified)

# Calculate the minification results
minified_file = Path(output_file_path)
minified_size = minified_file.stat().st_size
reduction = 100.0 - 100.0 * minified_size / original_size
print_message(f"Minified {minified_file.name} : {original_size} bytes -> {minified_size} bytes, {round(reduction)}% reduction")

# Output the minification result message
minified_file_name = minified_file.name.ljust(11, " ")
aggressive_text = (("non-" if not aggressive else "") + "aggressive").capitalize()
print_message(f"Minified {minified_file_name} : {aggressive_text}, "
f"{original_size} bytes -> {minified_size} bytes, {round(reduction)}% reduction")

def minimise_all_source_files():

def get_file_config(config: dict, file: Path) -> tuple | None:
"""
Return the minification configuration for the specified file

:param config: Dictionary of configuration values
:param file: Path for the file
:return: Tuple of the exclusion flag and the file minification settings
"""
# Check folder exclusions
parent_folder = file.parent.name
if parent_folder in config["exclude"]["folders"]:
return True, None

# Check file exclusions
if file.name in config["exclude"]["files"]:
return True, None

# Check for folder-level settings
if parent_folder in config["folders"].keys():
return False, config["folders"][parent_folder]

# Get the config for this file or, if not present, return a "safe" default
return False, config["files"].get(file.name, config["default"])


def minimise_all_source_files() -> None:
"""
Find all Python files and "minimise" them prior to transfer to the calculator
"""
Expand All @@ -157,11 +197,11 @@ def minimise_all_source_files():
with open(config_file, "r", encoding="utf-8") as f:
config = json.load(f)

# Set up folder paths
# # Set up folder paths
output_folder = prepare_output_folder()
source_folder = PROJECT_FOLDER / "src"

# Identify Python files that are *not* in excluded folders
# # Identify Python files that are *not* in excluded folders
python_files = (
p for p in Path(source_folder).rglob("*.py")
if set(config["exclude"]["folders"]).isdisjoint(p.parts)
Expand All @@ -170,9 +210,9 @@ def minimise_all_source_files():
# Sort the files and iterate over them, minifying them if they're not
# explicitly excluded
for file in sorted(python_files, key=lambda p: p.name.lower()):
if file.name not in config["exclude"]["files"]:
aggressive = file.name in config["aggressive"]
minify_file(file.absolute(), aggressive, config["preserve"], output_folder)
excluded, file_config = get_file_config(config, file)
if not excluded:
minify_file(file.absolute(), file_config["aggressive"], file_config["preserve"], output_folder)


if __name__ == "__main__" and "DOCBUILD" not in environ:
Expand Down
Loading