First Team Progect
import setuptools

with open('README.md', 'r', encoding='utf-8') as fh:
    long_description = fh.read()



setuptools.setup(
      name = 'py_delegator',
      version = '0.1.9',
      description = 'The First Team Project',
      long_description= long_description,
      long_description_content_type = 'text/markdown',
      url = 'https://github.com/paulmusquaro/py_delegator.git',
      author = 'Paul Musquaro, Serhii Mahdysiuk, Leonid Hutnyk, Dmytro Avrushchenko, Dmytro Rozhko',
      author_email = 'paulren9200@ukr.net, magdisyuk228@gmail.com, leohutnyk@gmail.com, trippyfren@gmail.com, dimalikegtr@gmail.com',
      packages = setuptools.find_namespace_packages(),
      include_package_data=True,
      install_requires=['requests==2.31.0'],
      entry_points = {'console_scripts': ['py_delegator = src.py_delegator.menu:main']},
      classifiers=[
          'Programming Language :: Python :: 3',
          'License :: OSI Approved :: MIT License',
          'Operating System :: OS Independent',
      ],
      python_requires='>=3.7',
      )
setup.py
paulmusquaro/py_delegator
import pickle
import re
from collections import UserDict
from collections import deque
from datetime import datetime, timedelta
from copy import deepcopy

contact = None
ab = None
was_saved = False

info = "Hello, this is your Addressbook! Commands available by request 'commands'"


def info_command():
    print("Available commands: 'record', 'view', 'add number', 'add email', 'upcoming', 'find', 'remove', 'edit', 'save', 'open'")


def check_empty_ab(func):
    def wrapper(self, *args, **kwargs):
        if not self.data:
            print("Addressbook is empty. Add contacts and try again!")
        else:
            return func(self, *args, **kwargs)

    return wrapper


class AddressBook(UserDict):
    def __init__(self):
        super().__init__()

    def add_record(self, record):
        if record["Name"] not in self.data.keys():
            self.data[record["Name"]] = record
            print("New contact was successfully added to addressbook")
        else:
            print(f"Contact {record['Name']} is already exists")

    @check_empty_ab
    def view(self):
        [last_key] = deque(self.data, maxlen=1)
        print("------------------------------------")
        for key, el in self.data.items():
            print("{:<18} {:<10}".format("Name:", el["Name"]))
            print("{:<18} {:<10}".format("Address: ", el["Address"]))
            print("{:<18} {:<10}".format("Phone number(s):", ", ".join(el["Number"])))
            print("{:<18} {:<10}".format("Email address(es):", ", ".join(el["Email"])))
            print("{:<18} {}".format("Birthdate:", el["Birthdate"]))
            if len(self.data) > 1 and key != last_key:
                print("************************************")
        print("------------------------------------")

    @check_empty_ab
    def add_phone(self):
        contact_enter = input("Choose contact for adding phonenumber: ")
        if contact_enter in self.data.keys():
            added = input("Enter additional phonenumber: ")
            if re.match(Contact._PATTERN_FOR_PHONE, added):
                self.data[contact_enter]["Number"].append(added)
                print(f"Additional phonenumber to contact {contact_enter} was successfully added")
            else:
                print("Invalid phone number. Try again next time!")
        else:
            print(f"Contact {contact_enter} isn't exist. Select one of your existing contacts!")

    @check_empty_ab
    def add_email(self):
        contact_enter = input("Choose contact for adding email address: ")
        if contact_enter in self.data.keys():
            added = input("Enter a backup email address: ")
            if re.match(Contact._PATTERN_FOR_EMAIL, added):
                self.data[contact_enter]["Email"].append(added)
                print(f"Backup email address to contact {contact_enter} was successfully added")
            else:
                print("Invalid email address. should be 'examples@com.ua'")
        else:
            print(f"Contact {contact_enter} isn't exist. Check the correctness of the data and try again!")

    @check_empty_ab
    def coming_birthdays(self):
        current_bd = dict()
        bd_actual = dict()
        period = int(input("Enter the end period (number of days) to search for upcoming celebrations: "))
        start_period = datetime.now().date()
        end_period = start_period + timedelta(days=period)
        for contact_name, contact_data in self.data.items():
            for key, value in contact_data.items():
                if key == "Birthdate" and value:
                    current_bd.update({contact_name: value.replace(year=datetime.now().year)})
        for name, date in current_bd.items():
            if date < start_period:
                bd_actual.update({name: date.replace(year=start_period.year + 1)})
            else:
                bd_actual.update({name: date})
        bd_dict = {name: date for name, date in bd_actual.items() if end_period >= date >= start_period}
        bd_dict = dict(sorted(bd_dict.items(), key=lambda item: item[1]))
        if bd_dict:
            result_string = f"Today is {start_period}"
            for name, date in bd_dict.items():
                result_string += f", celebrate {name} in {(date - start_period).days} day(s) ({date})"
        else:
            result_string = "There are no celebrations for this period"
        print(result_string)

    @check_empty_ab
    def find(self):
        search_str = str(input("Enter name or phonenumber for search (include partly): ")).lower()
        print("!" * 40)
        contact_find = False
        for name, phone in self.data.items():
            name_lower = name.lower()
            if search_str in name_lower or search_str in str([phone["Number"]]):
                if contact_find:
                    print("*" * 40)
                print("{:<18} {:<10}".format("Name:", phone["Name"]))
                print("{:<18} {:<10}".format("Address:", phone["Address"]))
                print("{:<18} {:<10}".format("Phone number(s):", ", ".join(phone["Number"])))
                print("{:<18} {:<10}".format("Email address(es):", ", ".join(phone["Email"])))
                print("{:<18} {}".format("Birthdate:", phone["Birthdate"]))
                contact_find = True
            else:
                continue
        if not contact_find:
            print("Unfortunately, there aren't exist contacts by your request")
        print("!" * 40)

    @check_empty_ab
    def remove_contact(self):
        index = input("Enter the name of contact for removing: ")
        if index in self.data:
            self.data.pop(index)
            print(f"Contact {index} was successfully removed from your addressbook")
        else:
            print("Removing is impossible. The specified contact does not exist")

    @check_empty_ab
    def edit_contact(self):
        enter = input("Enter the name of contact for editing: ")
        new_dict = {}
        contacts_for_delete = []
        for name, record in self.data.items():
            if enter == name:
                attribute = input("Select a section to edit: ")
                if attribute.lower() in ["name", "person", "subject"]:
                    new_value = input("Enter the new name: ")
                    if re.match(Contact._PATTERN_FOR_NAME, new_value) and new_value != name:
                        record["Name"] = new_value
                        new_dict.update({new_value: record})
                        contacts_for_delete.append(name)
                        print(f"Contact name {name} was successfully edited to {new_value}")
                    else:
                        print("Invalid name. Should starts with upper case and consists real name")
                elif attribute.lower() in ["email", "edit email", "email address"]:
                    new_value = input("Enter the new email address: ")
                    if re.match(Contact._PATTERN_FOR_EMAIL, new_value):
                        record["Email"] = [new_value]
                        print(f"{name}'s email address was successfully edited to {new_value}")
                    else:
                        print("Invalid email address. should be 'examples@com.ua'")
                elif attribute in ["phone", "edit phone", "phonenumber", "number"]:
                    new_value = input("Enter the new phone number: ")
                    if re.match(Contact._PATTERN_FOR_PHONE, new_value):
                        record["Number"] = [new_value]
                        print(f"{name}'s phone number was successfully edited to {new_value}")
                    else:
                        print("Invalid phone number. Try again!")
                elif attribute in ["date", "birthdate", "birthday", "birth"]:
                    new_value = input("Enter the new birthdate: ")
                    if new_value:
                        chars = "/ ,-"
                        for char in chars:
                            new_value = new_value.replace(char, ".")
                        true_value = datetime.strptime(new_value, "%d.%m.%Y").date()
                        record["Birthdate"] = true_value
                        print(f"{name}'s birthdate  was successfully edited to {true_value}")
                    else:
                        print("Invalid birthdate. Enter correct data next time!")
                elif attribute in ["address", "home address", "home"]:
                    new_value = input("Enter the new street address: ")
                    if re.match(Contact._PATTERN_FOR_ADRESS, new_value):
                        record["Address"] = new_value
                        print(f"{name}'s street address was successfully edited to {new_value}")
                    else:
                        print("Invalid address. Should be like 'Avengers St. 22/123'")
                else:
                    print(f"Section {attribute} doesn't exist")
        if contacts_for_delete:
            for el in contacts_for_delete:
                self.data.pop(el)
                del contacts_for_delete
            self.data.update(new_dict)
        sorted_dict = dict(sorted(self.data.items()))
        self.data = deepcopy(sorted_dict)

    @check_empty_ab
    def load(self):
        global was_saved
        file_name = input("Write name of file that should be created in format 'name.file_extension': ")
        if re.match(r"[\w\d]+\.\w+", file_name):
            with open(file_name, "wb") as file:
                pickle.dump(self.data, file)
                print("Data was successfully saved")
                was_saved = True
        else:
            print("Wrong filename format. Should be like 'example.extension'")

    def ab_cont(self):
        while True:
            file_name = input("Write name of file from where should be imported data in format 'name.file extension': ")
            if re.match(r"[\w\d]+\.\w+", file_name):
                try:
                    with open(file_name, "rb") as file:
                        self.data = pickle.load(file)
                        print("Data was opened")
                        break
                except FileNotFoundError:
                    print("There's no exist. Enter true filename!")
            else:
                print("Wrong filename format. Should be like 'example.extension'")

ab = AddressBook()


class Contact(UserDict):
    _PATTERN_FOR_NAME = r"^[A-Z][a-z]+(?:[-][A-Z][a-z]+)?(?:[ -][A-Z][a-z]+)?(?:[ ][A-Z][a-z]+)?(?:[-][A-Z][a-z]+)?\b"
    _PATTERN_FOR_PHONE = r'^\+?\d{11,16}$|^\d{10,12}$|^\+?\d{0,4}\(\d{3}\)\d{7,9}$|^\+?\d{0,4}\(\d{3}\)\d{1,3}-\d{1,3}-\d{1,3}$|^\(\d{3}\)\d{1,3}-\d{1,3}-\d{1,3}\|^\d{3}-\d{1,3}-\d{1,3}-\d{1,3}$'
    _PATTERN_FOR_ADRESS = r"(?:[a-zA-Z]+[\s-]){1,}St. \d+\/\d+"
    _PATTERN_FOR_EMAIL = r"[a-z\d_-]+@[a-z]+\.[a-z]+(?:\.[a-z]+)?"

    """
    Клас, що формує контактну книгу (всю інформацію про один певний контакт)
    """

    def __init__(self, name=None, adress=None, phonenumber=None, email=None, birthdate=None):
        super().__init__()
        self.__name = None
        self.name = name
        self.data["Name"] = self.name
        self.__address = None
        self.adress = adress
        self.data["Address"] = self.adress
        self.__phonenumber = []
        self.phonenumber = phonenumber
        self.data["Number"] = self.phonenumber
        self.__email = []
        self.email = email
        self.data["Email"] = self.email
        self.__birthdate = None
        self.birthdate = birthdate
        self.data["Birthdate"] = self.birthdate

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        if re.match(self._PATTERN_FOR_NAME, value):
            self.__name = value
        else:
            print(
                "Invalid name. Should starts with upper case and consists real name with/without patronymic and surname")

    @property
    def adress(self):
        return self.__address

    @adress.setter
    def adress(self, value):
        if value:
            if re.match(self._PATTERN_FOR_ADRESS, value):
                self.__address = value
            else:
                print(
                    "Invalid street address. Address format: 'Mykhaylo Kandinsky St. 23/422'. The address can also contain dashes")

    @property
    def phonenumber(self):
        return self.__phonenumber

    @phonenumber.setter
    def phonenumber(self, value):
        if value:
            if re.match(self._PATTERN_FOR_PHONE, value):
                self.__phonenumber = [value]
            else:
                print("Invalid phone number")

    @property
    def email(self):
        return self.__email

    @email.setter
    def email(self, value):
        if value:
            if re.match(self._PATTERN_FOR_EMAIL, value):
                self.__email = [value]
            else:
                print("Wrong email address: Format: 'name@example.com' or 'name@example.com.ua' ")

    @property
    def birthdate(self):
        return self.__birthdate

    @birthdate.setter
    def birthdate(self, value):
        try:
            if value:
                chars = "/ ,-"
                for char in chars:
                    value = value.replace(char, ".")
                self.__birthdate = datetime.strptime(value, "%d.%m.%Y").date()  # Валідація дати народження
        except ValueError:
            print("Invalid birtdate. Expecting 'DD.MM.YYYY', with punctuation (' ,-/'")


def write_contact():
    """
    Проміжна команда, яка створює контактну картку й одразу проходить всі валідації. Якщо все ок - записую в адрессбук
    """
    global contact
    print("Enter the following data to fill out the contact card:")
    while True:
        name = input(
            "Name (should starts with upper case and consists real name with/without patronymic and surname): ")
        if Contact(name).name:
            if Contact(name).name in ab.data.keys():
                print("The entered contact already exists. Enter a unique name.")
                continue
            break
    while True:
        address = input("Address (for example, 'Mykhaylo Kandinsky St. 23/422'):  ")
        if Contact(name, address).adress:
            break
    while True:
        phonenumber = input("Phone number: ")
        if Contact(name, address, phonenumber).phonenumber:
            break
    while True:
        email = input("Email (for example, 'name@example.com' or 'name@example.com.ua'): ")
        if Contact(name, address, phonenumber, email).email:
            break
    while True:
        birthdate = input("Birthdate (in format 'DD.MM.YYYY'): ")
        if Contact(name, address, phonenumber, email, birthdate).birthdate:
            break
    contact = Contact(name, address, phonenumber, email, birthdate)
    if contact.name and contact.adress and contact.phonenumber and contact.email and contact.birthdate:
        ab.add_record(contact)
    else:
        print("Відсутня контактна картка для додавання")


commands = {
    write_contact: "record",  # Команда, яка формує контактну картку і записує її одразу в адрессбук
    ab.view: "view",  # Перегляд одразу всього адрессбуку
    ab.add_phone: "add number",  # Команда, яка додає номер до існуючого контакту
    info_command: "commands",  # Інфо-команда, яка виводе список всіх доступних команд
    ab.add_email: "add email",  # Команда, яка додає email до існуючого контакту
    ab.coming_birthdays: "upcoming",
    # Команда, яка в залежності від заданої кількості днів виводить дні народження записаних контактів в періоді від сьогодні до заданої кількості днів
    ab.find: "find",  # Команда, яка знаходить контактів за номером або ім'ям
    ab.remove_contact: "remove",  # Команда, яка видаляє зазначений контакт
    ab.edit_contact: "edit",  # Команда, яка редагує атрибути зазначеного контакту
    ab.load: "save",  # Команда, яка зберігає файл
    ab.ab_cont: "open"  # Команда, що відкриває файл
}


def start():  # точка входу
    print(info)
    cont_data = input("Would you like to continue use previous data? (Y/n) ")
    while True:
        if cont_data == ("Y" or "y"):
           ab.ab_cont()
           break
        elif cont_data == ("n" or "n"):
            print("So, we will launch in first origin mode")
            break
        else:
            print("Try again!")
            cont_data = input("(Y/n): ")
    while True:
        command = input("Enter command --> ").lower()
        if command in commands.values():
            for key, value in commands.items():
                if command == value:
                    key()
        elif command in ["quit", "close", "bye", "exit"]:
            if ab.data and not was_saved:
                closing = input("Do you want to save data before exiting? (Y/n) ")
                if closing == ("Y" or "y"):
                    ab.load()
            print("Good bye! Your AddressBook helper will see you later :)")
            break
        else:
            print("Wrong command! Choose one of available commands!\n(Review available commands - 'commands')")


# start()  # запускається помічник тут

src/py_delegator/Addressbook.py
paulmusquaro/py_delegator
import calendar

class Calendar:
    def __init__(self, year, month):
        self.year = year
        self.month = month

    def show_calendar(self):
        if self.month < 1 or self.month > 12:
            print("The month is entered incorrectly.")
        else:
            cal = calendar.month(self.year, self.month)
            print("\n", cal)

def calend_main():
    year = int(input("Enter the year:"))
    month = int(input("Enter the month (1-12):"))
    
    my_calendar = Calendar(year, month)
    my_calendar.show_calendar()
src/py_delegator/calend.py
paulmusquaro/py_delegator
import requests
from datetime import datetime


class CurrencyConverter:
    def __init__(self, api_key):
        self.api_key = api_key
        self.url = 'https://openexchangerates.org/api/latest.json'

    def convert_currency(self, user_input):
        response = requests.get(self.url, params={'app_id': self.api_key, 'base': 'USD'})

        if response.status_code == 200:
            data = response.json()
            current_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

            if user_input == 'EXIT':
                return "Good Bye!"

            if user_input in data['rates']:
                rate = data['rates'][user_input]
                return f"{user_input} rate as of {current_datetime}: {rate}"
            else:
                return f"There is no data for currency: {user_input}"
        else:
            return f"An error occurred while receiving data. Status code: {response.status_code}"


def ex_main():
    api_key = '4c4e8fdc5f8b4a1b8c417b629d43d241'
    converter = CurrencyConverter(api_key)

    while True:
        user_input = input("Enter the currency code (e.g. EUR or GBP), or 'EXIT' to exit:").strip().upper()
        result = converter.convert_currency(user_input)
        print(result)
        if result == "Good Bye!":
            break
src/py_delegator/exchanger.py
paulmusquaro/py_delegator
# import sys
import re
import shutil
from pathlib import Path

class FileOrganizer:
    def __init__(self):
        self.JPEG_IMAGES = []
        self.JPG_IMAGES = []
        self.PNG_IMAGES = []
        self.SVG_IMAGES = []
        self.JFIF_IMAGES = []
        self.AVI_VIDEO = []
        self.MP4_VIDEO = []
        self.MOV_VIDEO = []
        self.MKV_VIDEO = []
        self.DOC_DOCUMENTS = []
        self.DOCX_DOCUMENTS = []
        self.TXT_DOCUMENTS = []
        self.PDF_DOCUMENTS = []
        self.XLSX_DOCUMENTS = []
        self.PPTX_DOCUMENTS = []
        self.MP3_AUDIO = []
        self.OGG_AUDIO = []
        self.WAV_AUDIO = []
        self.AMR_AUDIO = []
        self.ZIP_ARCHIVES = []
        self.GZ_ARCHIVES = []
        self.TAR_ARCHIVES = []
        self.MY_OTHER = []
        self.REGISTER_EXTENSIONS = {
            'JPEG':self.JPEG_IMAGES,
            'JPG':self.JPG_IMAGES,
            'PNG':self.PNG_IMAGES,
            'SVG':self.SVG_IMAGES,
            'JFIF':self.JFIF_IMAGES,
            'AVI':self.AVI_VIDEO,
            'MP4':self.MP4_VIDEO,
            'MOV':self.MOV_VIDEO,
            'MKV':self.MKV_VIDEO,
            'DOC':self.DOC_DOCUMENTS,
            'DOCX':self.DOCX_DOCUMENTS,
            'TXT':self.TXT_DOCUMENTS,
            'PDF':self.PDF_DOCUMENTS,
            'XLSX':self.XLSX_DOCUMENTS,
            'PPTX':self.PPTX_DOCUMENTS,
            'MP3':self.MP3_AUDIO,
            'OGG':self.OGG_AUDIO,
            'WAV':self.WAV_AUDIO,
            'AMR':self.AMR_AUDIO,
            'ZIP':self.ZIP_ARCHIVES,
            'GZ':self.GZ_ARCHIVES,
            'TAR':self.TAR_ARCHIVES}
        

        self.FOLDERS = []
        self.EXTENSIONS = set()
        self.UNKNOWN = set()

    def get_extension(self, filename: str) -> str:
        return Path(filename).suffix[1:].upper()

    def scan(self, folder: Path) -> None:
        for item in folder.iterdir():
            if item.is_dir():
                if item.name not in ('archives', 'video', 'audio', 'documents', 'images', 'MY_OTHER'):
                    self.FOLDERS.append(item)
                    self.scan(item)
                continue

            ext = self.get_extension(item.name)
            fullname = folder / item.name

            if not ext:
                self.MY_OTHER.append(fullname)
            else:
                try:
                    container = self.REGISTER_EXTENSIONS[ext]
                    self.EXTENSIONS.add(ext)
                    container.append(fullname)
                except KeyError:
                    self.UNKNOWN.add(ext)
                    self.MY_OTHER.append(fullname)

    def normalize(self, name: str) -> str:
        CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюяєіїґ'
        TRANSLATION = ("a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
                       "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja", "je", "ji", "g")
        TRANS = {}
        for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
            TRANS[ord(c)] = l
            TRANS[ord(c.upper())] = l.upper()

        t_name = name.translate(TRANS)
        t_name = re.sub(r'\W', '.', t_name)
        return t_name

    def handle_media(self, filename: Path, target_folder: Path):
        target_folder.mkdir(exist_ok=True, parents=True)
        filename.replace(target_folder / self.normalize(filename.name))

    def handle_other(self, filename: Path, target_folder: Path):
        target_folder.mkdir(exist_ok=True, parents=True)
        filename.replace(target_folder / self.normalize(filename.name))

    def handle_archive(self, filename: Path, target_folder: Path):
        target_folder.mkdir(exist_ok=True, parents=True)
        folder_for_file = target_folder / self.normalize(filename.name.replace(filename.suffix, ''))
        folder_for_file.mkdir(exist_ok=True, parents=True)

        try:
            shutil.unpack_archive(str(filename.resolve()), str(folder_for_file.resolve()))
        except shutil.ReadError:
            print(f'Це не архів {filename}!')
            folder_for_file.rmdir()
            return None

        filename.unlink()

    def handle_folder(self, folder: Path):
        try:
            folder.rmdir()
        except OSError:
            print(f'Помилка видалення папки {folder}')

    def organize_files(self, folder: Path):
        self.scan(folder)

        for file in self.JPEG_IMAGES:
            self.handle_media(file, folder / 'images' / 'JPEG')
        for file in self.JPG_IMAGES:
            self.handle_media(file, folder / 'images' / 'JPG')
        for file in self.PNG_IMAGES:
            self.handle_media(file, folder / 'images' / 'PNG')
        for file in self.SVG_IMAGES:
            self.handle_media(file, folder / 'images' / 'SVG')
        for file in self.JFIF_IMAGES:
            self.handle_media(file, folder / 'images' / 'JFIF')

        for file in self.AVI_VIDEO:
            self.handle_media(file, folder / 'video' / 'AVI')
        for file in self.MP4_VIDEO:
            self.handle_media(file, folder / 'video' / 'MP4')
        for file in self.MOV_VIDEO:
            self.handle_media(file, folder / 'video' / 'MOV')
        for file in self.MKV_VIDEO:
            self.handle_media(file, folder / 'video' / 'MKV')

        for file in self.DOC_DOCUMENTS:
            self.handle_media(file, folder / 'documents' / 'DOC')
        for file in self.DOCX_DOCUMENTS:
            self.handle_media(file, folder / 'documents' / 'DOCX')
        for file in self.TXT_DOCUMENTS:
            self.handle_media(file, folder / 'documents' / 'TXT')
        for file in self.PDF_DOCUMENTS:
            self.handle_media(file, folder / 'documents' / 'PDF')
        for file in self.XLSX_DOCUMENTS:
            self.handle_media(file, folder / 'documents' / 'XLSX')
        for file in self.PPTX_DOCUMENTS:
            self.handle_media(file, folder / 'documents' / 'PPTX')

        for file in self.MP3_AUDIO:
            self.handle_media(file, folder / 'audio' / 'MP3')
        for file in self.OGG_AUDIO:
            self.handle_media(file, folder / 'audio' / 'OGG')
        for file in self.WAV_AUDIO:
            self.handle_media(file, folder / 'audio' / 'WAV')
        for file in self.AMR_AUDIO:
            self.handle_media(file, folder / 'audio' / 'AMR')

        for file in self.ZIP_ARCHIVES:
            self.handle_archive(file, folder / 'archives' / 'ZIP')
        for file in self.GZ_ARCHIVES:
            self.handle_archive(file, folder / 'archives' / 'GZ')
        for file in self.TAR_ARCHIVES:
            self.handle_archive(file, folder / 'archives' / 'TAR')

        for file in self.MY_OTHER:
            self.handle_other(file, folder / 'MY_OTHER')

        for folder in self.FOLDERS[::-1]:
            self.handle_folder(folder)

def start(folder_path):
    folder_for_scan = Path(folder_path)
    print(f'Start in folder {folder_for_scan.resolve()}')
    file_organizer = FileOrganizer()
    file_organizer.organize_files(folder_for_scan.resolve())

src/py_delegator/file_sorter.py
paulmusquaro/py_delegator
# import importlib
import os
from .calend import calend_main
from .Addressbook import start as start_ab
from .notebook.nb_main import NoteManager
from .file_sorter import start as start_fs
from .exchanger import ex_main


class Menu:
    def __init__(self):
        self.choices = {
            1: ("file_sorter", start_fs),
            2: ("Addressbook", start_ab),
            3: ("notebook.nb_main", "nb_main"),
            4: ("calend", calend_main),
            5: ("exchanger", ex_main)
        }

    def make_decision(self, choice):
        module_name, function_name = self.choices.get(choice)
        
        if not module_name:
            return
        
        if choice == 3:
            note_folder = "notebook/notes"
            note_manager = NoteManager(note_folder)
            note_manager.nb_main()
            return True

        try:

            if choice == 1:
                directory_path = input("Enter the path to directory: ")
                if os.path.exists(directory_path) and os.path.isdir(directory_path):
                    # function = getattr(importlib.import_module(module_name), function_name)
                    # function(directory_path)
                    function_name(directory_path)
                else:
                    print("Invalid directory path. Please enter a valid directory path.")
            else:
                # function = getattr(importlib.import_module(module_name), function_name)
                # function()
                function_name()
        except ModuleNotFoundError:
            print("Module not found.")
        except AttributeError:
            print("Function not found in the module.")

def main():
    print("Choose an option:")
    print("1. File Sorter")
    print("2. Address Book")
    print("3. Notebook")
    print("4. Calendar")
    print("5. Exchanger")
    print("6. Exit")

    menu = Menu()
    option_3_called = False

    while True:
        try:
            choice = int(input("Enter your choice (1-6): "))
            if choice == 6:
                break
            # if not option_3_called or (option_3_called and choice != 4):
            else:
                option_3_called = menu.make_decision(choice)

        except ValueError:
            print("Invalid input. Please enter a number between 1 and 6.")

# if __name__ == "__main__":
#     main()

src/py_delegator/menu.py
paulmusquaro/py_delegator
import os


class NoteManager:
    def __init__(self, note_folder):
        self.note_folder = note_folder

    def create_note(self, title, content, tags):
        note_path = os.path.join(self.note_folder, f"{title}.txt")
        with open(note_path, "w") as file:
            file.write(f"Title: {title}\n")
            file.write(f"Content: {content}\n")
            file.write(f"Tags: {', '.join(tags)}\n")

    def search_notes_by_tags(self, tags):
        matching_notes = []
        for filename in os.listdir(self.note_folder):
            if filename.endswith(".txt"):
                with open(os.path.join(self.note_folder, filename), "r") as file:
                    content = file.read()
                    if all(tag in content for tag in tags):
                        matching_notes.append(content)

        if matching_notes:
            print(f"Notes containing tags {tags}")
            for note in matching_notes:
                print("-" * 20)
                print(note)
        else:
            print(f"No notes with tags {tags} were found")

    def search_notes_by_title(self, title):
        matching_notes = []
        for filename in os.listdir(self.note_folder):
            if filename.endswith(".txt") and title in filename:
                note_path = os.path.join(self.note_folder, filename)
                with open(note_path, "r") as file:
                    note_content = file.read()
                    matching_notes.append(note_content)

        if matching_notes:
            print(f"Notes, by name {title}")
            for note in matching_notes:
                print("-" * 20)
                print(note)
        else:
            print(f"No notes with title {title} found")

    def display_all_notes(self):
        for filename in os.listdir(self.note_folder):
            if filename.endswith(".txt"):
                note_path = os.path.join(self.note_folder, filename)
                with open(note_path, "r") as file:
                    note_content = file.read()
                    print(note_content)
                    print("-" * 20)

    def edit_note(self, title, new_content):
        note_path = os.path.join(self.note_folder, f"{title}.txt")
        if os.path.exists(note_path):
            with open(note_path, "w") as file:
                file.write(f"Title: {title}\n")
                file.write(f"Content: {new_content}\n")

    def delete_note(self, title):
        note_path = os.path.join(self.note_folder, f"{title}.txt")
        if os.path.exists(note_path):
            os.remove(note_path)

    def nb_main(self):

        if not os.path.exists(self.note_folder):
            os.makedirs(self.note_folder)

        while True:
            print("\nMenu:")
            print("1. Create a note")
            print("2. Search notes by tags")
            print("3. Search for notes by name")
            print("4. Show all notes")
            print("5. Edit note")
            print("6. Delete note")
            print("7. Exit")

            choice = input("Select an option: ")

            if choice == "1":
                title = input("Enter a name for the note:")
                content = input("Enter the content of the note:")
                tags = input("Enter tags (through commas): ").split(", ")
                self.create_note(title, content, tags)
                print("Note created.")

            elif choice == "2":
                tags_to_search = input("Enter tags to search (through commas): ").split(", ")
                self.search_notes_by_tags(tags_to_search)

            elif choice == "3":
                title_to_search = input("Enter a name to search for: ")
                self.search_notes_by_title(title_to_search)

            elif choice == "4":
                print("\n" + ("-" * 20))
                self.display_all_notes()

            elif choice == "5":
                title = input("Enter the name of the note to edit: ")
                new_content = input("Enter the new content of the note:")
                self.edit_note(title, new_content)
                print("The note has been updated.")

            elif choice == "6":
                title = input("Enter the name of the note to delete: ")
                self.delete_note(title)
                print("Note deleted.")

            elif choice == "7":
                break

            else:
                print("Wrong choice. Please select the correct option.")


if __name__ == "__main__":
    """

    ------------------------------
    from notebook.nb_main import NoteManager
    note_folder = "notebook/notes"
    manager = NoteManager(note_folder)
    manager.nb_main()
    ------------------------------
    """

    note_folder = "notes"
    manager = NoteManager(note_folder)
    manager.nb_main()

src/py_delegator/notebook/nb_main.py
paulmusquaro/py_delegator