Compare commits

...

2 Commits

Author SHA1 Message Date
da7e 1cf669e6f8 fix(ex4): add wraps to every functions;
mypy compliance
2026-03-29 13:33:56 +02:00
da7e 1dfeee81e3 C'est fini la piscine !!!! 2026-03-21 13:47:54 +01:00
6 changed files with 94 additions and 256 deletions
-222
View File
@@ -1,222 +0,0 @@
"""
FuncMage Chronicles - Data Generator Helper
Generates test data for all exercises to help learners test their
implementations
"""
import random
from typing import List, Dict, Any
class FuncMageDataGenerator:
"""Generate test data for FuncMage Chronicles exercises."""
# Fantasy-themed data pools
MAGE_NAMES = [
"Alex",
"Jordan",
"Riley",
"Casey",
"Morgan",
"Sage",
"River",
"Phoenix",
"Ember",
"Storm",
"Luna",
"Nova",
"Zara",
"Kai",
"Rowan",
"Ash"]
ELEMENTS = [
"fire",
"ice",
"lightning",
"earth",
"wind",
"water",
"light",
"shadow"]
SPELL_NAMES = [
"fireball", "heal", "shield", "lightning", "freeze", "earthquake",
"tornado", "tsunami", "flash", "darkness", "meteor", "blizzard"
]
ARTIFACT_NAMES = [
"Crystal Orb",
"Fire Staff",
"Ice Wand",
"Lightning Rod",
"Earth Shield",
"Wind Cloak",
"Water Chalice",
"Shadow Blade",
"Light Prism",
"Storm Crown"]
ARTIFACT_TYPES = ["weapon", "focus", "armor", "accessory", "relic"]
ENCHANTMENT_TYPES = [
"Flaming",
"Frozen",
"Shocking",
"Earthen",
"Windy",
"Flowing",
"Radiant",
"Dark"]
@classmethod
def generate_mages(cls, count: int = 5) -> List[Dict[str, Any]]:
"""Generate a list of mages with random attributes."""
mages = []
for _ in range(count):
mage = {
'name': random.choice(cls.MAGE_NAMES),
'power': random.randint(50, 100),
'element': random.choice(cls.ELEMENTS)
}
mages.append(mage)
return mages
@classmethod
def generate_artifacts(cls, count: int = 5) -> List[Dict[str, Any]]:
"""Generate a list of magical artifacts."""
artifacts = []
for _ in range(count):
artifact = {
'name': random.choice(cls.ARTIFACT_NAMES),
'power': random.randint(60, 120),
'type': random.choice(cls.ARTIFACT_TYPES)
}
artifacts.append(artifact)
return artifacts
@classmethod
def generate_spells(cls, count: int = 6) -> List[str]:
"""Generate a list of spell names."""
return random.sample(cls.SPELL_NAMES, min(count, len(cls.SPELL_NAMES)))
@classmethod
def generate_spell_powers(cls, count: int = 5) -> List[int]:
"""Generate a list of spell power values."""
return [random.randint(10, 50) for _ in range(count)]
@classmethod
def generate_enchantment_items(cls, count: int = 5) -> List[str]:
"""Generate a list of items to be enchanted."""
items = [
"Sword",
"Shield",
"Staff",
"Wand",
"Armor",
"Ring",
"Amulet",
"Cloak"]
return random.sample(items, min(count, len(items)))
@classmethod
def print_exercise_data(cls, exercise_num: int):
"""Print formatted test data for a specific exercise."""
print(f"=== Exercise {exercise_num} Test Data ===")
if exercise_num == 0:
print("# Lambda Sanctum Test Data")
print("artifacts =", cls.generate_artifacts(4))
print("mages =", cls.generate_mages(5))
print("spells =", cls.generate_spells(4))
elif exercise_num == 1:
print("# Higher Realm Test Data")
print("# Use these in your test functions:")
print("test_values =", [random.randint(5, 25) for _ in range(3)])
print("test_targets =", ["Dragon", "Goblin", "Wizard", "Knight"])
elif exercise_num == 2:
print("# Memory Depths Test Data")
print(
"initial_powers =", [
random.randint(
20, 80) for _ in range(3)])
print(
"power_additions =", [
random.randint(
5, 20) for _ in range(5)])
print(
"enchantment_types =",
random.sample(
cls.ENCHANTMENT_TYPES,
3))
print("items_to_enchant =", cls.generate_enchantment_items(4))
elif exercise_num == 3:
print("# Ancient Library Test Data")
print("spell_powers =", cls.generate_spell_powers(6))
print("operations = ['add', 'multiply', 'max', 'min']")
print(
"fibonacci_tests =", [
random.randint(
8, 20) for _ in range(3)])
elif exercise_num == 4:
print("# Master's Tower Test Data")
print("test_powers =", [random.randint(5, 30) for _ in range(4)])
print("spell_names =", random.sample(cls.SPELL_NAMES, 4))
print("mage_names =", random.sample(cls.MAGE_NAMES, 6))
print("invalid_names = ['Jo', 'A', 'Alex123', 'Test@Name']")
print()
def main():
"""Interactive data generator for FuncMage Chronicles."""
print("🧙‍♀️ FuncMage Chronicles - Data Generator Helper 🧙‍♂️")
print("=" * 50)
print()
while True:
print("Choose an option:")
print("0. Generate data for Exercise 0 (Lambda Sanctum)")
print("1. Generate data for Exercise 1 (Higher Realm)")
print("2. Generate data for Exercise 2 (Memory Depths)")
print("3. Generate data for Exercise 3 (Ancient Library)")
print("4. Generate data for Exercise 4 (Master's Tower)")
print("5. Generate data for ALL exercises")
print("6. Generate custom mage data")
print("7. Generate custom artifact data")
print("q. Quit")
print()
choice = input("Enter your choice: ").strip().lower()
if choice == 'q':
print("May your functions be pure and your closures be strong! 🌟")
break
elif choice in ['0', '1', '2', '3', '4']:
FuncMageDataGenerator.print_exercise_data(int(choice))
elif choice == '5':
for i in range(5):
FuncMageDataGenerator.print_exercise_data(i)
elif choice == '6':
count = int(
input("How many mages to generate? (default 5): ") or 5)
print("mages =", FuncMageDataGenerator.generate_mages(count))
print()
elif choice == '7':
count = int(
input("How many artifacts to generate? (default 5): ") or 5)
print(
"artifacts =",
FuncMageDataGenerator.generate_artifacts(count))
print()
else:
print("Invalid choice. Please try again.")
print()
if __name__ == "__main__":
main()
+8 -3
View File
@@ -1,4 +1,7 @@
def artifact_sorter(artifacts: list[dict]) -> list[dict]: from typing import Any
def artifact_sorter(artifacts: list[dict[Any, Any]]) -> list[dict[Any, Any]]:
try: try:
return sorted(artifacts, key=lambda artifact: artifact["power"]) return sorted(artifacts, key=lambda artifact: artifact["power"])
except KeyError as err: except KeyError as err:
@@ -6,7 +9,9 @@ def artifact_sorter(artifacts: list[dict]) -> list[dict]:
return artifacts return artifacts
def power_filter(mages: list[dict], min_power: int) -> list[dict]: def power_filter(
mages: list[dict[Any, Any]], min_power: int
) -> list[dict[Any, Any]]:
try: try:
return list(filter(lambda x: x["power"] >= min_power, mages)) return list(filter(lambda x: x["power"] >= min_power, mages))
except KeyError as err: except KeyError as err:
@@ -18,7 +23,7 @@ def spell_transformer(spells: list[str]) -> list[str]:
return list(map(lambda x: "* " + x + " *", spells)) return list(map(lambda x: "* " + x + " *", spells))
def mage_stats(mages: list[dict]) -> dict: def mage_stats(mages: list[dict[Any, Any]]) -> dict[str, int | float]:
try: try:
max_power = max(mages, key=lambda mage: mage["power"]) max_power = max(mages, key=lambda mage: mage["power"])
min_power = min(mages, key=lambda mage: mage["power"]) min_power = min(mages, key=lambda mage: mage["power"])
+7 -7
View File
@@ -1,22 +1,22 @@
from typing import Callable from typing import Any, Callable
def spell_combiner(spell1: Callable, spell2: Callable) -> Callable: def spell_combiner(spell1: Callable, spell2: Callable) -> Callable:
def combiner(*args): def combiner(*args: Any) -> tuple[Any, Any]:
return (spell1(*args), spell2(*args)) return (spell1(*args), spell2(*args))
return combiner return combiner
def power_amplifier(base_spell: Callable, multiplier: int) -> Callable: def power_amplifier(base_spell: Callable, multiplier: int) -> Callable:
def multiplie(*args): def multiply(*args: Any) -> Any:
return base_spell(*args) * multiplier return base_spell(*args) * multiplier
return multiplie return multiply
def conditional_caster(condition: Callable, spell: Callable) -> Callable: def conditional_caster(condition: Callable, spell: Callable) -> Callable:
def cond_res(*args, **kwargs): def cond_res(*args: Any, **kwargs: Any) -> Any:
if condition(*args, **kwargs): if condition(*args, **kwargs):
return spell(args[0]) return spell(args[0])
else: else:
@@ -26,7 +26,7 @@ def conditional_caster(condition: Callable, spell: Callable) -> Callable:
def spell_sequence(spells: list[Callable]) -> Callable: def spell_sequence(spells: list[Callable]) -> Callable:
def sequence(*args, **kwargs): def sequence(*args: Any, **kwargs: Any) -> list[Any]:
return [res(*args, **kwargs) for res in spells] return [res(*args, **kwargs) for res in spells]
return sequence return sequence
@@ -56,7 +56,7 @@ def main() -> None:
print("\n=== power_amplifier ===") print("\n=== power_amplifier ===")
amplifier = power_amplifier(pow_2, 4) amplifier = power_amplifier(pow_2, 4)
print(f"multiplie 5 pow_2 by 4: {amplifier(5)}") print(f"multiply 5 pow_2 by 4: {amplifier(5)}")
print("\n=== conditional_caster ===") print("\n=== conditional_caster ===")
caster = conditional_caster(isinstance, fireball) caster = conditional_caster(isinstance, fireball)
+1 -2
View File
@@ -34,7 +34,6 @@ def memory_vault() -> dict[str, Callable]:
storage = {} storage = {}
def store(to_store: dict[str, str]) -> None: def store(to_store: dict[str, str]) -> None:
nonlocal storage
for data in to_store: for data in to_store:
storage[data] = to_store[data] storage[data] = to_store[data]
@@ -47,7 +46,7 @@ def memory_vault() -> dict[str, Callable]:
return {"store": store, "recall": recall} return {"store": store, "recall": recall}
def main(): def main() -> None:
print("===mage_counter===\n") print("===mage_counter===\n")
count = mage_counter() count = mage_counter()
print(f"1 : {count()}") print(f"1 : {count()}")
+3 -3
View File
@@ -1,6 +1,5 @@
from functools import lru_cache, reduce, partial, singledispatch from functools import lru_cache, reduce, partial, singledispatch
import operator as op import operator as op
import re
from typing import Callable, Any from typing import Callable, Any
@@ -27,6 +26,7 @@ def partial_enchanter(base_enchantment: Callable) -> dict[str, Callable]:
} }
@lru_cache
def memoized_fibonacci(n: int) -> int: def memoized_fibonacci(n: int) -> int:
if n < 2: if n < 2:
return n return n
@@ -35,7 +35,7 @@ def memoized_fibonacci(n: int) -> int:
def spell_dispatcher() -> Callable: def spell_dispatcher() -> Callable:
@singledispatch @singledispatch
def basic(arg: Any) -> str: def basic(arg: Any) -> Any:
return arg return arg
@basic.register(int) @basic.register(int)
@@ -47,7 +47,7 @@ def spell_dispatcher() -> Callable:
return f"apply {arg}" return f"apply {arg}"
@basic.register(list) @basic.register(list)
def basic_list(arg: list) -> str: def basic_list(arg: list[Any]) -> str:
res = "" res = ""
for cast in arg: for cast in arg:
res += f"cast {cast}\n" res += f"cast {cast}\n"
+67 -11
View File
@@ -5,43 +5,99 @@ from functools import wraps
def spell_timer(func: Callable) -> Callable: def spell_timer(func: Callable) -> Callable:
@wraps(func) @wraps(func)
def print_time(*args, **kwargs) -> Any: def print_time(*args: Any, **kwargs: Any) -> Any:
print(f"Casting {func.__name__}") print(f"Casting {func.__name__}")
start = time.time() start = time.time()
res = func(args, kwargs) res = func(*args, **kwargs)
print(f"Spell completed int {time.time() - start} seconds") print(f"Spell completed int {(time.time() - start):.3f} seconds")
return res return res
return print_time return print_time
def power_validator(min_power: int) -> Callable: def power_validator(min_power: int) -> Callable:
def check_power(power: int, func: Callable) -> str | Any: def check_power(func: Callable) -> str | Any:
@wraps(func)
def fn(*args: Any) -> str | Any:
try: try:
if power < min_power: if args[2] < min_power:
return "Insufficient power for this spell" return "Insufficient power for this spell"
return func() return func(*args)
except Exception: except Exception as err:
print(err)
return "invalid input" return "invalid input"
return fn
return check_power return check_power
def retry_spell(max_attempts: int) -> Callable: def retry_spell(max_attempts: int) -> Callable:
def try_spell(func: Callable) -> str | Any: def try_spell(func: Callable) -> str | Any:
@wraps(func)
def fn(*args: Any) -> Any:
for i in range(max_attempts): for i in range(max_attempts):
try: try:
return func() return func(*args)
except Exception: except Exception:
print(f"Spell failed, retrying... ({i + 1}/{max_attempts})") print(
f"Spell failed, retrying... ({i + 1}/{max_attempts})"
)
continue continue
return f"Spell casting failed after {max_attempts} attempts" return f"Spell casting failed after {max_attempts} attempts"
return fn
return try_spell return try_spell
class MageGuild: class MageGuild:
@staticmethod @staticmethod
def validate_mage_name(name: str) -> bool: ... def validate_mage_name(name: str) -> bool:
return len(name) >= 3 and all(x.isalpha() or x.isspace() for x in name)
def cast_spell(self, spell_name: str, power: int) -> str: ... @power_validator(10)
def cast_spell(self, spell_name: str, power: int) -> str:
return f"Successfully cast {spell_name} with {power} power"
def main() -> None:
import time
@spell_timer
def fireball() -> str:
time.sleep(0.5)
return "Fireball cast!"
@retry_spell(3)
def make_exception(exception: Exception) -> None:
raise exception
guild = MageGuild()
print("===spell_timer===\n")
print(f"Result: {fireball()}")
print("\n===power_validator===\n")
print(f"Valid: {guild.cast_spell('meteorite de caca', 15)}")
print(f"INvalid: {guild.cast_spell('meteorite de caca', 5)}")
print("\n===retry_spell===\n")
print(f"Invalid: {make_exception(Exception())}")
print("\n======MageGuild======\n")
print("\n===validate_mage_name===\n")
print(f"Less than 3 chars: {MageGuild.validate_mage_name('op')}")
print(f"Special char: {MageGuild.validate_mage_name('ope!')}")
print(
"valid: "
f"{MageGuild.validate_mage_name('Bonjour a tous c est vendredi')}"
)
print("\n===cast_spell===\n")
print(f"Valid: {guild.cast_spell('Lightning', 15)}")
print(f"Invalid: {guild.cast_spell('Lightning', 5)}")
if __name__ == "__main__":
main()