eval_python/main.py
2025-12-01 17:46:26 +01:00

108 lines
3.6 KiB
Python

"""
This module has no real meaning.
Simply implemented for evaluating students.
"""
from pathlib import Path
from itertools import chain
import re
import string
def list_filenames_of_log_files(*foldernames) -> list:
"""
List all the `*.log` files stored in the folders specified by foldernames.
This method returns a list containing the corresponding strings. Ordered in alphabetical order.
This method does not print anything.
:param foldernames:
:return: list of filenames
:raises FileNotFoundError: If one of the speficied folders does not exist
"""
def walk(folder):
if not folder.exists():
raise FileNotFoundError(f"{folder} does not exist")
for subfold, childfolds, files in folder.walk():
for f in files:
if ".log" in f:
yield subfold / f
# final cast as list would generally be omited but due to the test expecting
# an indexable object, this cast is need. It would be more idiomatic to return
# a generator and iterate over it tho.
return list(chain(*[walk(Path(foldername)) for foldername in foldernames]))
def list_ipv4_listed_in_logfiles(*foldernames) -> list:
"""
Parse all the `*.log` files stored in the folders specified by foldernames.
This method returns a list of ip adresses stored in those files.
This method does not print anything.
Only IPv4 format are listed
No duplicates are returned.
:param foldernames:
:return: list of ips
:raises FileNotFoundError: If one of the speficied folders does not exist
"""
def get_ip_from_file(file):
matcher = re.compile(r"(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})")
with open(file) as f:
for line in f:
if match := matcher.search(line):
yield match.group()
# cast to a set to delete duplicates
# cast to a list 'caus the test is hardcoded to get a list
return list(set(chain(*[get_ip_from_file(file) for file in list_filenames_of_log_files(*foldernames)])))
def cryptarithme(message: str = "SEND + MORE = MONEY") -> list:
"""
The `message` is a formatted mathematical operation.
Each letter represents a number between 0 and 9.
Each letter represents a different value.
Find the value for each letter so that the full sentence is true.
Knowing that if the word is longer than 1 letter,
the first letter of the word cannot be a 0.
It can occur that several results are possible.
If so, all solutions must be returned in differents dictionnairies.
The order is not relevant.
Example : A + A = C returns
[
{"A" : 1, "C" : 2},
{"A" : 2, "C" : 4},
{"A" : 3, "C" : 6},
{"A" : 4, "C" : 8}
]
:param message: The string to analyse
:return: List of dictionnaries with the following format : {
'letter1': value1,
'letter2': value2
}
:raises ValueError: If the string cannot be parsed properly.
:raises CryptarithmeError : If the string is not a possible Cryptarithme
"""
# check for syntax
for i, character in enumerate(message):
if character not in [*string.ascii_uppercase, "+", "=", " "]:
raise ValueError(f"illegal character {character} at {i}")
if len([i for i in message if i == "="]) >= 2 or len([i for i in message if i == "+"]) >= 2:
raise ValueError("too much =")
return message
class CryptarithmeError(Exception):
pass
if __name__ == "__main__":
# list_filenames_of_log_files('data')
# list_ipv4_listed_in_logfiles('data')
# cryptarithme('A + A +A= B')
pass