Skip to content

Instantly share code, notes, and snippets.

@isakb
Created June 22, 2024 18:22
Show Gist options
  • Save isakb/74302cb9e659f8aa8352e0b6bd71e378 to your computer and use it in GitHub Desktop.
Save isakb/74302cb9e659f8aa8352e0b6bd71e378 to your computer and use it in GitHub Desktop.
Enterprise version of is_even
# Enterprise version of is_even.
# (Don't use this in a startup.)
#
# python is_even.py 1
# False
# python is_even.py 2
# True
# python is_even.py 101
# False
# python is_even.py 1
# False
import logging
import re
from dataclasses import dataclass
from typing import Dict, Generator, Optional
import yaml
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
DEFAULT_THRESHOLD = 1000
def pagerduty_alert(message: str) -> None:
"""
Simulates sending an alert to PagerDuty.
Args:
message (str): The alert message.
"""
logger.error(f"PagerDuty Alert: {message}")
class Config:
"""
Configuration management class for loading and accessing configuration settings.
Args:
config_path (str): Path to the configuration file.
Attributes:
config (dict): Dictionary holding configuration settings.
"""
even_check_config: Dict[str, Optional[str]]
def __init__(self, config_path: str = 'config.yaml') -> None:
self.even_check_config = self._load_config(config_path)
def _load_config(self, path: str) -> dict:
"""
Loads configuration from a YAML file.
Args:
path (str): Path to the YAML configuration file.
Returns:
dict: Configuration settings.
"""
with open(path, 'r') as file:
return yaml.safe_load(file)
def get(self, key: str, default: Optional[str] = None) -> Optional[str]:
"""
Gets a configuration value by key.
Args:
key (str): The configuration key.
default (Optional[str]): The default value if key is not found.
Returns:
Optional[str]: The configuration value.
"""
return self.even_check_config.get(key, default)
class EvenChecker:
"""
Class to check if numbers are even using a recursive method.
Args:
config (Config): Configuration object.
Attributes:
memo (dict): Memoization dictionary for caching results.
threshold (int): Recursion depth threshold.
"""
memo: Dict[int, bool]
threshold: int = 1000
def __init__(self, config: Config) -> None:
self.memo = {}
try:
config_threshold = config.get('recursion_threshold')
if config_threshold is not None:
self.threshold = int(config_threshold)
else:
logger.info("Recursion threshold not found in config, using default")
self.threshold = DEFAULT_THRESHOLD
except ValueError:
logger.error("Invalid recursion threshold value in config, using default")
self.threshold = 1000
def is_even(self, a: int) -> bool:
"""
Checks if a number is even.
Args:
a (int): The number to check.
Returns:
bool: True if the number is even, False otherwise.
Examples:
>>> config = Config('config.yaml')
>>> checker = EvenChecker(config)
>>> checker.is_even(4)
True
>>> checker.is_even(7)
False
"""
if a in self.memo:
return self.memo[a]
result = self._recursive_check(a)
self.memo[a] = result
return result
def _recursive_check(self, a: int, depth: int = 0) -> bool:
"""
Recursively checks if a number is even.
Args:
a (int): The number to check.
depth (int): The current recursion depth.
Returns:
bool: True if the number is even, False otherwise.
"""
if depth > self.threshold:
pagerduty_alert("Recursion depth exceeded threshold")
return False
if a == 0:
return True
if a == 1:
return False
gen = self._generate_next(a)
next_num = next(gen)
return self._recursive_check(next_num, depth + 1)
def _generate_next(self, a: int) -> Generator[int, None, None]:
"""
Generates the next number to check.
Args:
a (int): The current number.
Yields:
int: The next number to check.
"""
yield a - 2
class NumberParser:
"""
Class to parse strings and check if extracted numbers are even.
Args:
checker (EvenChecker): EvenChecker instance.
Attributes:
checker (EvenChecker): EvenChecker instance.
"""
def __init__(self, checker: EvenChecker) -> None:
self.checker = checker
def parse_and_check(self, number_string: str) -> bool:
"""
Parses a string to extract a number and checks if it is even.
Args:
number_string (str): The string containing the number.
Returns:
bool: True if the extracted number is even, False otherwise.
Examples:
>>> config = Config('config.yaml')
>>> checker = EvenChecker(config)
>>> parser = NumberParser(checker)
>>> parser.parse_and_check("The number is 42")
True
>>> parser.parse_and_check("The number is 13")
False
"""
match = re.search(r'\d+', number_string)
if match:
number = int(match.group(0))
logger.info(f"Checking if {number} is even")
return self.checker.is_even(number)
logger.warning("No number found in string")
return False
@dataclass
class EvenCheckerFactory:
"""
Factory class to create EvenChecker instances.
Args:
config_path (str): Path to the configuration file.
"""
config_path: str = 'config.yaml'
def create_even_checker(self) -> EvenChecker:
"""
Creates an EvenChecker instance.
Returns:
EvenChecker: A new EvenChecker instance.
"""
config = Config(self.config_path)
return EvenChecker(config)
if __name__ == "__main__":
import sys
number = int(sys.argv[1])
config = Config('config.yaml')
checker = EvenChecker(config)
result = checker.is_even(number)
print(result)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment