From 9fd77e5b536ae616a97cdebd799ec0e15594d095 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:17:29 +0000 Subject: [PATCH 1/5] Initial plan From f669c5c74cad03e1fded4140592143fcf0bee306 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:29:04 +0000 Subject: [PATCH 2/5] Add strict type checking to _freeze_module.py - Added complete type annotations to all functions, parameters, and return types - Added runtime type checking function _check_type() that enforces strict typing - All functions now validate parameter types and raise TypeError if incorrect - Added comprehensive docstrings explaining type requirements - Module header variable now has explicit type annotation - Tested both normal operation and type error detection Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- Programs/_freeze_module.py | 148 +++++++++++++++++++++++++++++++++---- 1 file changed, 133 insertions(+), 15 deletions(-) diff --git a/Programs/_freeze_module.py b/Programs/_freeze_module.py index ba638ee..3099ecb 100644 --- a/Programs/_freeze_module.py +++ b/Programs/_freeze_module.py @@ -1,4 +1,4 @@ -"""Python implementation of Programs/_freeze_module.c +"""Python implementation of Programs/_freeze_module.c with strict type checking. The pure Python implementation uses same functions and arguments as the C implementation. @@ -7,32 +7,121 @@ The generated byte code is slightly different because compile() sets the PyCF_SOURCE_IS_UTF8 flag and objects have a reference count > 1. Marshal adds the `FLAG_REF` flag and creates a reference `hashtable`. + +This version enforces strict type checking with runtime validation. +An exception is thrown if something is not typed correctly. """ import marshal import sys +from typing import TextIO -header = "/* Auto-generated by Programs/_freeze_module.py */" +header: str = "/* Auto-generated by Programs/_freeze_module.py */" + + +def _check_type(value, expected_type, param_name: str) -> None: + """Enforce strict type checking at runtime. + + Args: + value: The value to check + expected_type: The expected type(s) + param_name: Name of the parameter for error messages + + Raises: + TypeError: If the value doesn't match the expected type + """ + if not isinstance(value, expected_type): + raise TypeError( + f"Parameter '{param_name}' must be of type {expected_type.__name__}, " + f"got {type(value).__name__}" + ) def read_text(inpath: str) -> bytes: + """Read text from a file and return as bytes. + + Args: + inpath: Path to the input file + + Returns: + The file contents as bytes + + Raises: + TypeError: If inpath is not a string + """ + _check_type(inpath, str, "inpath") + with open(inpath, "rb") as f: - return f.read() + result: bytes = f.read() + + return result def compile_and_marshal(name: str, text: bytes) -> bytes: - filename = f"" + """Compile Python source code and marshal it. + + Args: + name: Name identifier for the frozen module + text: Python source code as bytes + + Returns: + Marshalled bytecode + + Raises: + TypeError: If parameters are not of correct types + """ + _check_type(name, str, "name") + _check_type(text, bytes, "text") + + filename: str = f"" # exec == Py_file_input code = compile(text, filename, "exec", optimize=0, dont_inherit=True) - return marshal.dumps(code) + result: bytes = marshal.dumps(code) + + return result def get_varname(name: str, prefix: str) -> str: - return f"{prefix}{name.replace('.', '_')}" + """Generate a C variable name from a module name. + + Args: + name: Module name + prefix: Prefix for the variable name + + Returns: + C-compatible variable name + + Raises: + TypeError: If parameters are not strings + """ + _check_type(name, str, "name") + _check_type(prefix, str, "prefix") + + result: str = f"{prefix}{name.replace('.', '_')}" + return result -def write_code(outfile, marshalled: bytes, varname: str) -> None: - data_size = len(marshalled) +def write_code(outfile: TextIO, marshalled: bytes, varname: str) -> None: + """Write marshalled code as C array to output file. + + Args: + outfile: Output file object + marshalled: Marshalled bytecode + varname: C variable name for the array + + Raises: + TypeError: If parameters are not of correct types + """ + _check_type(marshalled, bytes, "marshalled") + _check_type(varname, str, "varname") + + # Check that outfile has a write method (duck typing for file-like objects) + if not hasattr(outfile, 'write') or not callable(getattr(outfile, 'write')): + raise TypeError( + f"Parameter 'outfile' must be a file-like object with write() method" + ) + + data_size: int = len(marshalled) outfile.write(f"const unsigned char {varname}[] = {{\n") @@ -44,23 +133,52 @@ def write_code(outfile, marshalled: bytes, varname: str) -> None: def write_frozen(outpath: str, inpath: str, name: str, marshalled: bytes) -> None: + """Write frozen module to output file. + + Args: + outpath: Path to output file + inpath: Path to input file (unused but kept for API compatibility) + name: Module name + marshalled: Marshalled bytecode + + Raises: + TypeError: If parameters are not of correct types + """ + _check_type(outpath, str, "outpath") + _check_type(inpath, str, "inpath") + _check_type(name, str, "name") + _check_type(marshalled, bytes, "marshalled") + with open(outpath, "w") as outfile: outfile.write(header) outfile.write("\n") - arrayname = get_varname(name, "_Py_M__") + arrayname: str = get_varname(name, "_Py_M__") write_code(outfile, marshalled, arrayname) -def main(): +def main() -> None: + """Main entry point for the freeze_module program. + + Validates command-line arguments and processes the module freezing. + + Raises: + SystemExit: If incorrect number of arguments provided + TypeError: If any type validation fails + """ if len(sys.argv) != 4: sys.exit("need to specify the name, input and output paths\n") - name = sys.argv[1] - inpath = sys.argv[2] - outpath = sys.argv[3] + name: str = sys.argv[1] + inpath: str = sys.argv[2] + outpath: str = sys.argv[3] + + # Validate that arguments are strings + _check_type(name, str, "name") + _check_type(inpath, str, "inpath") + _check_type(outpath, str, "outpath") - text = read_text(inpath) - marshalled = compile_and_marshal(name, text) + text: bytes = read_text(inpath) + marshalled: bytes = compile_and_marshal(name, text) write_frozen(outpath, inpath, name, marshalled) From b72a44eb4ca5f650e9ebe1921e24c12deaa3bb76 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:30:09 +0000 Subject: [PATCH 3/5] Fix code review feedback - improve error handling and remove redundant checks - Use getattr to safely access __name__ attribute for better type error messages - Remove redundant type checks for sys.argv elements (guaranteed to be strings) Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- Programs/_freeze_module.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Programs/_freeze_module.py b/Programs/_freeze_module.py index 3099ecb..e41591a 100644 --- a/Programs/_freeze_module.py +++ b/Programs/_freeze_module.py @@ -31,8 +31,10 @@ def _check_type(value, expected_type, param_name: str) -> None: TypeError: If the value doesn't match the expected type """ if not isinstance(value, expected_type): + # Handle types that may not have __name__ attribute + type_name = getattr(expected_type, '__name__', str(expected_type)) raise TypeError( - f"Parameter '{param_name}' must be of type {expected_type.__name__}, " + f"Parameter '{param_name}' must be of type {type_name}, " f"got {type(value).__name__}" ) @@ -171,11 +173,6 @@ def main() -> None: name: str = sys.argv[1] inpath: str = sys.argv[2] outpath: str = sys.argv[3] - - # Validate that arguments are strings - _check_type(name, str, "name") - _check_type(inpath, str, "inpath") - _check_type(outpath, str, "outpath") text: bytes = read_text(inpath) marshalled: bytes = compile_and_marshal(name, text) From 8af79e6e8bee0cb8da9d9a6fbe4baf8696035e3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:48:37 +0000 Subject: [PATCH 4/5] Enforce type annotations at function definition time - Added @strict_types decorator that validates all parameters have type hints - Functions without type annotations now raise TypeError at definition time - All functions in the module decorated with @strict_types - def my_func(var1, var2): raises TypeError (no annotations) - def my_func(var1: str, var2: int): is accepted (has annotations) Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- Programs/_freeze_module.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Programs/_freeze_module.py b/Programs/_freeze_module.py index e41591a..954aea7 100644 --- a/Programs/_freeze_module.py +++ b/Programs/_freeze_module.py @@ -10,15 +10,42 @@ reference `hashtable`. This version enforces strict type checking with runtime validation. An exception is thrown if something is not typed correctly. +All function parameters must have type annotations. """ +import inspect import marshal import sys -from typing import TextIO +from typing import TextIO, get_type_hints header: str = "/* Auto-generated by Programs/_freeze_module.py */" +def strict_types(func): + """Decorator that enforces type annotations on all parameters. + + Raises: + TypeError: If any parameter lacks a type annotation + """ + sig = inspect.signature(func) + + # Check that all parameters have annotations + for param_name, param in sig.parameters.items(): + if param.annotation == inspect.Parameter.empty: + raise TypeError( + f"Function '{func.__name__}' parameter '{param_name}' " + f"must have a type annotation" + ) + + # Check that return type is annotated + if sig.return_annotation == inspect.Signature.empty: + raise TypeError( + f"Function '{func.__name__}' must have a return type annotation" + ) + + return func + + def _check_type(value, expected_type, param_name: str) -> None: """Enforce strict type checking at runtime. @@ -39,6 +66,7 @@ def _check_type(value, expected_type, param_name: str) -> None: ) +@strict_types def read_text(inpath: str) -> bytes: """Read text from a file and return as bytes. @@ -59,6 +87,7 @@ def read_text(inpath: str) -> bytes: return result +@strict_types def compile_and_marshal(name: str, text: bytes) -> bytes: """Compile Python source code and marshal it. @@ -83,6 +112,7 @@ def compile_and_marshal(name: str, text: bytes) -> bytes: return result +@strict_types def get_varname(name: str, prefix: str) -> str: """Generate a C variable name from a module name. @@ -103,6 +133,7 @@ def get_varname(name: str, prefix: str) -> str: return result +@strict_types def write_code(outfile: TextIO, marshalled: bytes, varname: str) -> None: """Write marshalled code as C array to output file. @@ -134,6 +165,7 @@ def write_code(outfile: TextIO, marshalled: bytes, varname: str) -> None: outfile.write("};\n") +@strict_types def write_frozen(outpath: str, inpath: str, name: str, marshalled: bytes) -> None: """Write frozen module to output file. @@ -158,6 +190,7 @@ def write_frozen(outpath: str, inpath: str, name: str, marshalled: bytes) -> Non write_code(outfile, marshalled, arrayname) +@strict_types def main() -> None: """Main entry point for the freeze_module program. From b0af5a66cdae1d09f5ec512de2c59d64a754b204 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:50:16 +0000 Subject: [PATCH 5/5] Add type annotations to helper functions per code review - Added type annotations to strict_types decorator (func: F -> F) - Added type annotations to _check_type parameters (value: Any, expected_type: Type) - Removed unused get_type_hints import - Added TypeVar and proper typing imports for decorator - All functions now have complete type annotations including helpers Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- Programs/_freeze_module.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Programs/_freeze_module.py b/Programs/_freeze_module.py index 954aea7..90146b7 100644 --- a/Programs/_freeze_module.py +++ b/Programs/_freeze_module.py @@ -16,12 +16,14 @@ All function parameters must have type annotations. import inspect import marshal import sys -from typing import TextIO, get_type_hints +from typing import Any, Callable, TextIO, Type, TypeVar header: str = "/* Auto-generated by Programs/_freeze_module.py */" +F = TypeVar('F', bound=Callable[..., Any]) -def strict_types(func): + +def strict_types(func: F) -> F: """Decorator that enforces type annotations on all parameters. Raises: @@ -46,7 +48,7 @@ def strict_types(func): return func -def _check_type(value, expected_type, param_name: str) -> None: +def _check_type(value: Any, expected_type: Type, param_name: str) -> None: """Enforce strict type checking at runtime. Args: