diff --git a/GNUmakefile b/GNUmakefile index 6cbf3c408..debd82020 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -74,7 +74,7 @@ vendor/crdp: vendor-deps: | clear-vendor-dirs vendor/Heap-Layers vendor/printf/printf.cpp vendor/crdp mypy: - -mypy $(PYTHON_SOURCES) + -mypy --no-warn-unused-ignores $(PYTHON_SOURCES) format: black clang-format prettier diff --git a/scalene/replacement_sem_lock.py b/scalene/replacement_sem_lock.py index 755f1536d..f3f2d877a 100644 --- a/scalene/replacement_sem_lock.py +++ b/scalene/replacement_sem_lock.py @@ -4,15 +4,10 @@ import threading from multiprocessing.synchronize import Lock from scalene.scalene_profiler import Scalene -from typing import Any - - -def _recreate_replacement_sem_lock(): - return ReplacementSemLock() - +from typing import Any, Callable, Optional, Tuple class ReplacementSemLock(multiprocessing.synchronize.Lock): - def __init__(self, ctx=None): + def __init__(self, ctx: Optional[multiprocessing.context.DefaultContext] = None) -> None: # Ensure to use the appropriate context while initializing if ctx is None: ctx = multiprocessing.get_context() @@ -34,5 +29,5 @@ def __enter__(self) -> bool: def __exit__(self, *args: Any) -> None: super().__exit__(*args) - def __reduce__(self): - return (_recreate_replacement_sem_lock, ()) + def __reduce__(self) -> Tuple[Callable[[], Any], Tuple[()]]: + return (ReplacementSemLock, ()) diff --git a/scalene/replacement_signal_fns.py b/scalene/replacement_signal_fns.py index 5220e11fe..d0abafbe9 100644 --- a/scalene/replacement_signal_fns.py +++ b/scalene/replacement_signal_fns.py @@ -3,7 +3,7 @@ import sys from scalene.scalene_profiler import Scalene - +from typing import Any @Scalene.shim def replacement_signal_fns(scalene: Scalene) -> None: @@ -24,7 +24,7 @@ def old_raise_signal(s): else: new_cpu_signal = signal.SIGFPE - def replacement_signal(signum: int, handler): # type: ignore + def replacement_signal(signum: int, handler: Any) -> Any: all_signals = scalene.get_all_signals_set() timer_signal, cpu_signal = scalene.get_timer_signals() timer_signal_str = signal.strsignal(signum) @@ -90,7 +90,7 @@ def replacement_setitimer(which, seconds, interval=0.0): # type: ignore signal.setitimer = replacement_setitimer signal.siginterrupt = replacement_siginterrupt - signal.signal = replacement_signal + signal.signal = replacement_signal # type: ignore if sys.version_info >= (3, 8): signal.raise_signal = replacement_raise_signal os.kill = replacement_kill diff --git a/scalene/scalene_analysis.py b/scalene/scalene_analysis.py index 81f6bd8c0..37ea4738b 100644 --- a/scalene/scalene_analysis.py +++ b/scalene/scalene_analysis.py @@ -3,7 +3,7 @@ import os import sys -from typing import cast, Dict, List, Tuple +from typing import cast, Any, Dict, List, Tuple if sys.version_info < (3, 9): # ast.unparse only supported as of 3.9 @@ -21,11 +21,12 @@ def is_native(package_name: str) -> bool: result = False try: package = importlib.import_module(package_name) - package_dir = os.path.dirname(package.__file__) - for root, dirs, files in os.walk(package_dir): - for filename in files: - if filename.endswith(".so") or filename.endswith(".pyd"): - return True + if package.__file__: + package_dir = os.path.dirname(package.__file__) + for root, dirs, files in os.walk(package_dir): + for filename in files: + if filename.endswith(".so") or filename.endswith(".pyd"): + return True result = False except ImportError: result = False @@ -140,7 +141,7 @@ def find_outermost_loop(src: str) -> Dict[int, Tuple[int, int]]: tree = ast.parse(src) regions = {} - def walk(node, current_outermost_region, outer_class): + def walk(node : ast.AST, current_outermost_region : Any, outer_class : Any) -> None: nonlocal regions if isinstance( node, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef) @@ -172,6 +173,7 @@ def walk(node, current_outermost_region, outer_class): ast.AsyncFunctionDef, ] + assert node.end_lineno for line in range(node.lineno, node.end_lineno + 1): # NOTE: we update child nodes first (in the recursive call), # so what we want this statement to do is attribute any lines that we haven't already diff --git a/scalene/scalene_apple_gpu.py b/scalene/scalene_apple_gpu.py index 835782523..eada389c5 100644 --- a/scalene/scalene_apple_gpu.py +++ b/scalene/scalene_apple_gpu.py @@ -8,7 +8,7 @@ class ScaleneAppleGPU: """Wrapper class for Apple integrated GPU statistics.""" - def __init__(self, sampling_frequency=100) -> None: + def __init__(self, sampling_frequency: int = 100) -> None: assert platform.system() == "Darwin" self.cmd = ( 'DYLD_INSERT_LIBRARIES="" ioreg -r -d 1 -w 0 -c "IOAccelerator"' diff --git a/scalene/scalene_json.py b/scalene/scalene_json.py index 5bae9aa1b..48266e6ac 100644 --- a/scalene/scalene_json.py +++ b/scalene/scalene_json.py @@ -69,7 +69,7 @@ def __init__(self) -> None: def compress_samples( self, samples: List[Any], max_footprint: float - ) -> List[Any]: + ) -> Any: if len(samples) <= self.max_sparkline_samples: return samples # Try to reduce the number of samples with the diff --git a/scalene/scalene_jupyter.py b/scalene/scalene_jupyter.py index 9876b1f71..a9fa7c67a 100644 --- a/scalene/scalene_jupyter.py +++ b/scalene/scalene_jupyter.py @@ -55,7 +55,7 @@ def do_GET(self) -> None: except FileNotFoundError: print("Scalene error: profile file not found.") elif self.path == "/shutdown": - self.server.should_shutdown = True + self.server.should_shutdown = True # type: ignore self.send_response(204) # self._send_response("Server is shutting down...") else: diff --git a/scalene/scalene_output.py b/scalene/scalene_output.py index 9d5ec21e0..4e4557be7 100644 --- a/scalene/scalene_output.py +++ b/scalene/scalene_output.py @@ -102,7 +102,7 @@ def output_profile_line( fname=fname, fname_print=fname, line_no=line_no, - line=line, + line=str(line), stats=stats, profile_this_code=profile_this_code, force_print=force_print, diff --git a/scalene/scalene_parseargs.py b/scalene/scalene_parseargs.py index 4b91ba116..6eb10dc74 100644 --- a/scalene/scalene_parseargs.py +++ b/scalene/scalene_parseargs.py @@ -352,6 +352,7 @@ def parse_args() -> Tuple[argparse.Namespace, List[str]]: # Parse out all Scalene arguments. # https://stackoverflow.com/questions/35733262/is-there-any-way-to-instruct-argparse-python-2-7-to-remove-found-arguments-fro args, left = parser.parse_known_args() + # Hack to simplify functionality for Windows platforms. if sys.platform == "win32": args.on = True @@ -394,7 +395,11 @@ def parse_args() -> Tuple[argparse.Namespace, List[str]]: print(f"Scalene version {scalene_version} ({scalene_date})") if not args.ipython: sys.exit(-1) - args = ( - [] - ) # We use this to indicate that we should not run further in IPython. + # Clear out the namespace. We do this to indicate that we should not run further in IPython. + for arg in list(args.__dict__): + delattr(args, arg) + # was: + # args = ( + # [] + # ) # We use this to indicate that we should not run further in IPython. return args, left diff --git a/scalene/scalene_profiler.py b/scalene/scalene_profiler.py index a59574bdc..54144bb21 100644 --- a/scalene/scalene_profiler.py +++ b/scalene/scalene_profiler.py @@ -1702,7 +1702,7 @@ def profile_code( exec(code, the_globals, the_locals) except SystemExit as se: # Intercept sys.exit and propagate the error code. - exit_status = se.code + exit_status = se.code if type(se.code) == int else 1 except KeyboardInterrupt: # Cleanly handle keyboard interrupts (quits execution and dumps the profile). print("Scalene execution interrupted.") @@ -1992,7 +1992,7 @@ def run_profiler( print("Scalene: no input file specified.") sys.exit(1) except SystemExit as e: - exit_status = e.code + exit_status = e.code if type(e.code) == int else 1 except StopJupyterExecution: pass diff --git a/scalene/scalene_statistics.py b/scalene/scalene_statistics.py index d1c2b38f7..056f15735 100644 --- a/scalene/scalene_statistics.py +++ b/scalene/scalene_statistics.py @@ -447,7 +447,7 @@ def merge_stats(self, the_dir_name: pathlib.Path) -> None: for filename in self.per_line_footprint_samples: for lineno in self.per_line_footprint_samples[filename]: self.per_line_footprint_samples[filename][lineno].sort( - key=lambda x: x[0] # type: ignore + key=lambda x: x[0] ) self.increment_per_line_samples( self.memory_malloc_count, x.memory_malloc_count diff --git a/scalene/test_runningstats.py b/scalene/test_runningstats.py index 4a330b61b..e5ba64832 100644 --- a/scalene/test_runningstats.py +++ b/scalene/test_runningstats.py @@ -5,7 +5,7 @@ import statistics from hypothesis import given - +from typing import List @given( st.lists( @@ -15,7 +15,7 @@ min_size=2, ) ) -def test_running_stats(values): +def test_running_stats(values: List[float]) -> None: rstats = runningstats.RunningStats() for value in values: rstats.push(value) diff --git a/scalene/test_scalene_json.py b/scalene/test_scalene_json.py index 0963699e4..89b17bd46 100644 --- a/scalene/test_scalene_json.py +++ b/scalene/test_scalene_json.py @@ -3,6 +3,7 @@ from hypothesis import given from hypothesis.strategies import floats, lists +from typing import Any, List class TestScaleneJSON: # Define strategies for the input variables @@ -17,7 +18,7 @@ class TestScaleneJSON: ) @given(size_in_mb) - def test_memory_consumed_str(self, size_in_mb): + def test_memory_consumed_str(self, size_in_mb: int) -> None: formatted = scalene_json.ScaleneJSON().memory_consumed_str(size_in_mb) assert isinstance(formatted, str) if size_in_mb < 1024: @@ -28,7 +29,7 @@ def test_memory_consumed_str(self, size_in_mb): assert formatted.endswith("TB") @given(time_in_ms) - def test_time_consumed_str(self, time_in_ms): + def test_time_consumed_str(self, time_in_ms: int) -> None: formatted = scalene_json.ScaleneJSON().time_consumed_str(time_in_ms) assert isinstance(formatted, str) if time_in_ms < 1000: @@ -42,7 +43,7 @@ def test_time_consumed_str(self, time_in_ms): assert not formatted.startswith("0") @given(samples, max_footprint) - def test_compress_samples(self, samples, max_footprint): + def test_compress_samples(self, samples : List[Any], max_footprint: int) -> None: compressed = scalene_json.ScaleneJSON().compress_samples( samples, max_footprint )