diff --git a/grizzly/args.py b/grizzly/args.py index 1b498b7a..eb6a713e 100644 --- a/grizzly/args.py +++ b/grizzly/args.py @@ -13,6 +13,7 @@ from os.path import exists from pathlib import Path from platform import system +from types import MappingProxyType from typing import Iterable, List, Optional from FTB.ProgramConfiguration import ProgramConfiguration @@ -47,18 +48,20 @@ def add_arguments(self, actions: Iterable[Action]) -> None: class CommonArgs: - IGNORABLE = ("log-limit", "memory", "timeout") DEFAULT_IGNORE = ("log-limit", "timeout") - - def __init__(self) -> None: - # log levels for console logging - self._level_map = { + IGNORABLE = ("log-limit", "memory", "timeout") + # log levels for console logging + LEVEL_MAP = MappingProxyType( + { "CRIT": CRITICAL, "ERROR": ERROR, "WARN": WARNING, "INFO": INFO, "DEBUG": DEBUG, } + ) + + def __init__(self) -> None: self.parser = ArgumentParser( formatter_class=SortingHelpFormatter, conflict_handler="resolve" @@ -71,7 +74,7 @@ def __init__(self) -> None: self.parser.add_argument("binary", type=Path, help="Firefox binary to run") self.parser.add_argument( "--log-level", - choices=sorted(self._level_map), + choices=sorted(self.LEVEL_MAP), default="INFO", help="Configure console logging (default: %(default)s)", ) @@ -295,7 +298,7 @@ def sanity_check(self, args: Namespace) -> None: if args.launch_attempts < 1: self.parser.error("--launch-attempts must be >= 1") - args.log_level = self._level_map[args.log_level] + args.log_level = self.LEVEL_MAP[args.log_level] if args.log_limit < 0: self.parser.error("--log-limit must be >= 0") diff --git a/grizzly/reduce/strategies/beautify.py b/grizzly/reduce/strategies/beautify.py index 03428b85..f3085422 100644 --- a/grizzly/reduce/strategies/beautify.py +++ b/grizzly/reduce/strategies/beautify.py @@ -11,7 +11,7 @@ from abc import ABC, abstractmethod from logging import getLogger from pathlib import Path -from typing import Generator, List, Match, Optional, Set, Tuple, cast +from typing import FrozenSet, Generator, List, Match, Optional, Tuple, cast from lithium.testcases import TestcaseLine @@ -64,8 +64,8 @@ class _BeautifyStrategy(Strategy, ABC): tag_name: Tag name to search for in other (non-native) extensions. """ - all_extensions: Set[str] - ignore_files = {TEST_INFO, "prefs.js"} + all_extensions: FrozenSet[str] + ignore_files = frozenset((TEST_INFO, "prefs.js")) import_available: bool import_name: str native_extension: str @@ -276,7 +276,7 @@ class CSSBeautify(_BeautifyStrategy): definitions. """ - all_extensions = {".css", ".htm", ".html", ".xhtml"} + all_extensions = frozenset((".css", ".htm", ".html", ".xhtml")) import_available = HAVE_CSSBEAUTIFIER import_name = "cssbeautifier" name = "cssbeautify" @@ -315,7 +315,7 @@ class JSBeautify(_BeautifyStrategy): compound statements. """ - all_extensions = {".js", ".htm", ".html", ".xhtml"} + all_extensions = frozenset((".js", ".htm", ".html", ".xhtml")) import_available = HAVE_JSBEAUTIFIER import_name = "jsbeautifier" name = "jsbeautify" diff --git a/loki/loki.py b/loki/loki.py index 2b40f1eb..e80ae1d4 100644 --- a/loki/loki.py +++ b/loki/loki.py @@ -22,7 +22,7 @@ class Loki: - BYTE_ORDERS = {"<", ">", "@", "!", "="} + BYTE_ORDERS = frozenset(("<", ">", "@", "!", "=")) __slots__ = ("aggr", "byte_order") diff --git a/sapphire/core.py b/sapphire/core.py index cec8fdbb..20944fcb 100644 --- a/sapphire/core.py +++ b/sapphire/core.py @@ -10,7 +10,7 @@ from socket import SO_REUSEADDR, SOL_SOCKET, gethostname, socket from ssl import PROTOCOL_TLS_SERVER, SSLContext, SSLSocket from time import perf_counter, sleep -from typing import Any, Callable, Dict, Iterable, Optional, Tuple, Union, cast +from typing import Any, Callable, Iterable, Mapping, Optional, Tuple, Union, cast from .certificate_bundle import CertificateBundle from .connection_manager import ConnectionManager @@ -200,7 +200,7 @@ def serve_path( forever: bool = False, required_files: Optional[Iterable[str]] = None, server_map: Optional[ServerMap] = None, - ) -> Tuple[Served, Dict[str, Path]]: + ) -> Tuple[Served, Mapping[str, Path]]: """Serve files in path. The status codes include: @@ -216,7 +216,7 @@ def serve_path( This is meant to be used with continue_cb. required_files: Files that need to be served in order to exit the serve loop. - server_map (ServerMap): + server_map: Map of server includes, dynamic requests and redirects. Returns: Status code and files served. diff --git a/sapphire/job.py b/sapphire/job.py index faaa9d50..15156063 100644 --- a/sapphire/job.py +++ b/sapphire/job.py @@ -13,7 +13,8 @@ from pathlib import Path from queue import Queue from threading import Event, Lock -from typing import Any, Dict, Iterable, NamedTuple, Optional, Set, Tuple, Union, cast +from types import MappingProxyType +from typing import Any, Iterable, Mapping, NamedTuple, Optional, Set, Tuple, Union, cast from .server_map import DynamicResource, FileResource, RedirectResource, ServerMap @@ -50,13 +51,15 @@ class ServedTracker(NamedTuple): class Job: # MIME_MAP is used to support new or uncommon mime types. # Definitions in here take priority over mimetypes.guess_type(). - MIME_MAP = { - ".avif": "image/avif", - ".bmp": "image/bmp", - ".ico": "image/x-icon", - ".wave": "audio/x-wav", - ".webp": "image/webp", - } + MIME_MAP = MappingProxyType( + { + ".avif": "image/avif", + ".bmp": "image/bmp", + ".ico": "image/x-icon", + ".wave": "audio/x-wav", + ".webp": "image/webp", + } + ) __slots__ = ( "_complete", @@ -260,7 +263,7 @@ def remove_pending(self, file_name: str) -> bool: return not self._pending.files @property - def served(self) -> Dict[str, Path]: + def served(self) -> Mapping[str, Path]: """Served files. Args: @@ -270,7 +273,7 @@ def served(self) -> Dict[str, Path]: Mapping of URLs to files on disk. """ with self._served.lock: - return {entry.url: entry.target for entry in self._served.files} + return MappingProxyType({x.url: x.target for x in self._served.files}) @property def status(self) -> Served: