diff --git a/Lectures/py_lec_10.pptx b/Lectures/py_lec_10.pptx index 51d4f90..5281ba2 100644 Binary files a/Lectures/py_lec_10.pptx and b/Lectures/py_lec_10.pptx differ diff --git a/Lectures/py_lec_12.pdf b/Lectures/py_lec_12.pdf new file mode 100644 index 0000000..715cc4e Binary files /dev/null and b/Lectures/py_lec_12.pdf differ diff --git a/Lectures/py_lec_14.pptx b/Lectures/py_lec_14.pptx index 83c5b35..3ec7c12 100644 Binary files a/Lectures/py_lec_14.pptx and b/Lectures/py_lec_14.pptx differ diff --git a/Practice/AKapralova/KapralovaDz7.3.py b/Practice/AKapralova/KapralovaDz7.3.py new file mode 100644 index 0000000..7820c5b --- /dev/null +++ b/Practice/AKapralova/KapralovaDz7.3.py @@ -0,0 +1,45 @@ +class ATM: + def __init__(self, name, balance=0): + self._name = name + self._balance = float(balance) + + def about_atm(self): + print(f"Банкомат: {self._name} Баланс: {self._balance}") + + def operation(self): + print("Банкомат может осуществлять операции получения и выдачи наличных.") + + def get_money(self, money): + self._balance += money + + def give_money(self, money): + if self._balance - money < 0: + print(f"В Банкомате:{self._name} недостаточно денежных средств.") + else: + self._balance -= money + + +class GetGiveATM(ATM): + pass + + +class OnlineATM(ATM): + def operation(self): + super().operation() + print("Банкомат может осуществлять онлайн платежи.") + + def online_payment(self): + print(f'{self._name}: Совершен онлайн платеж') + + +b1 = GetGiveATM("Сбер", 1000) + +b2 = OnlineATM("ВТБ", 2000) +b2.online_payment() + +lst = [b1, b2] +for i in lst: + i.about_atm() + i.operation() + i.get_money(100) + i.give_money(200) diff --git a/Practice/AKapralova/KapralovaDz8.1.py b/Practice/AKapralova/KapralovaDz8.1.py new file mode 100644 index 0000000..07a7f7d --- /dev/null +++ b/Practice/AKapralova/KapralovaDz8.1.py @@ -0,0 +1,30 @@ +# Реализовать итератор, который бы "читал" заданный текст по параграфам. +# Символ параграфа задается отдельно. +class ParagraphIterator: + + def __init__(self, text, paragraph_symbol): + self.text = text + self.paragraph_symbol = paragraph_symbol + self.current_paragraph = 0 + + def __iter__(self): + return self + + def __next__(self): + res = '' + if self.current_paragraph > len(self.text) - 1: + raise StopIteration + while self.text[self.current_paragraph] != self.paragraph_symbol: + res += self.text[self.current_paragraph] + self.current_paragraph += 1 + if self.current_paragraph >= len(self.text): + break + else: + self.current_paragraph += 1 + return res + + +text = "Дама сдавала в багаж: Диван. Чемодан. Саквояж. Картину. Корзину. Картонку. И маленькую собачонку." + +for i in ParagraphIterator(text, "."): + print(i) diff --git a/Practice/AKapralova/KapralovaDz8.2.py b/Practice/AKapralova/KapralovaDz8.2.py new file mode 100644 index 0000000..c537c53 --- /dev/null +++ b/Practice/AKapralova/KapralovaDz8.2.py @@ -0,0 +1,9 @@ +# Написать генератор для построчного чтения файла. +def read_by_line(file_path): + with open(file_path, 'r') as file: + for line in file: + yield line + + +for line in read_by_line('2txt'): + print(line) diff --git a/Practice/AKapralova/KapralovaDz8.3.py b/Practice/AKapralova/KapralovaDz8.3.py new file mode 100644 index 0000000..dc5faa7 --- /dev/null +++ b/Practice/AKapralova/KapralovaDz8.3.py @@ -0,0 +1,20 @@ +# Напишите свой менеджер контекста, замеряющий и показывающий время исполнения кода внутри него. +import time + + +class Timer: + def __enter__(self): + self.start_time = time.time() + + def __exit__(self, exc_type, exc_value, traceback): + elapsed_time = time.time() - self.start_time + print(f"Время работы программы: {elapsed_time} сек.") + + +with Timer(): + # lst = [1, 3, 24, 2, 3, 7] + # lst.sort() + # print(lst) + enumerated_numbers = enumerate(range(1, 10001)) + for i, j in enumerated_numbers: + print(i, j) diff --git a/Practice/AKapralova/KapralovaDz8.4.py b/Practice/AKapralova/KapralovaDz8.4.py new file mode 100644 index 0000000..cd42e9b --- /dev/null +++ b/Practice/AKapralova/KapralovaDz8.4.py @@ -0,0 +1,12 @@ +import itertools + + +lst1 = list(itertools.chain([1, 2, 3], [4, 5], [6, 7])) +print(lst1) + +lst = ['hello', 'i', 'write', 'cool', 'code'] +lst2 = list(itertools.filterfalse(lambda x: len(x) < 5, lst)) +print(lst2) + +lst3 = list(itertools.combinations('password', 4)) +print(lst3) diff --git a/Practice/AKapralova/KapralovaDz9.2.py b/Practice/AKapralova/KapralovaDz9.2.py new file mode 100644 index 0000000..52863c5 --- /dev/null +++ b/Practice/AKapralova/KapralovaDz9.2.py @@ -0,0 +1,16 @@ +import datetime + + +def fun_count(date1, date2): + count = 0 + current_date = date1 + while current_date <= date2: + if current_date.weekday() < 5: + count += 1 + current_date += datetime.timedelta(days=1) + return count + + +date1 = datetime.date(2018, 8, 21) +date2 = datetime.date(2023, 8, 3) +print(f"Количество рабочих дней: {fun_count(date1, date2)}") diff --git a/Practice/AKapralova/KapralovaDz9.3.py b/Practice/AKapralova/KapralovaDz9.3.py new file mode 100644 index 0000000..de35426 --- /dev/null +++ b/Practice/AKapralova/KapralovaDz9.3.py @@ -0,0 +1,19 @@ +import os +import shutil +import time + + +folder_path = input("Укажите полный путь до папки: ") +while True: + for root, dirs, files in os.walk(folder_path): + for file in files: + file_path = os.path.join(root, file) + file_age = time.time() - os.path.getctime(file_path) + if file_age > 60: + os.remove(file_path) + for dir in dirs: + dir_path = os.path.join(root, dir) + dir_age = time.time() - os.path.getctime(dir_path) + if dir_age > 120: + shutil.rmtree(dir_path) + time.sleep(10) diff --git a/Practice/AKapralova/KapralovaDz9.4.py b/Practice/AKapralova/KapralovaDz9.4.py new file mode 100644 index 0000000..510dae1 --- /dev/null +++ b/Practice/AKapralova/KapralovaDz9.4.py @@ -0,0 +1,41 @@ +import pickle +import random + + +class Human: + def __init__(self, name, surname, age, residence): + self.name = name + self.surname = surname + self.age = age + self.residence = residence + + def __str__(self): + return f"{self.name} {self.surname}, возраст: {self.age}, проживает в городе {self.residence}." + + +def create(num_instances): + first_names = ["Анна", "Юлия", "Полина", "Олеся", "Татьяна"] + last_names = ["Капралова", "Сидорова", "Смирнова", "Иванова", "Петрова"] + residences = ["Нижний Новгород", "Екатеринбург", "Москва", "Иваново", "Кстово"] + humans = [] + for i in range(num_instances): + name = random.choice(first_names) + surname = random.choice(last_names) + age = random.randint(18, 25) + residence = random.choice(residences) + human = Human(name, surname, age, residence) + humans.append(human) + with open("human.data", "wb") as file: + pickle.dump(humans, file) + + +def read(): + with open("human.data", "rb") as file: + humans = pickle.load(file) + for human in humans: + print(human) + + +if __name__ == "__main__": + create(5) + read() diff --git a/Practice/Fedorov/HW_9/9+.1.py b/Practice/Fedorov/HW_9/9+.1.py new file mode 100644 index 0000000..e5f6ac1 --- /dev/null +++ b/Practice/Fedorov/HW_9/9+.1.py @@ -0,0 +1,8 @@ +# Используя моржовый оператор, по заданному списку элементов lst = [“10”, “5”, “a”, “3”, “b”] +# создать новый список, содержащий квадраты тех элементов исходного списка, +# которые можно привести к типу Число и которые в численном представлении кратны 5. + +lst = ["10", "5", "a", "3", "b"] + +new_lst = [x**2 for i in lst if i.isdigit() and (x := int(i)) % 5 == 0] +print(new_lst) diff --git a/Practice/Fedorov/HW_9/9+.2.py b/Practice/Fedorov/HW_9/9+.2.py new file mode 100644 index 0000000..dc9eb70 --- /dev/null +++ b/Practice/Fedorov/HW_9/9+.2.py @@ -0,0 +1,17 @@ +# Используя структурное сопоставление с шаблонами (match/case), +# написать чат-бота, отвечающего на вопросы «Привет», «Как дела?», «Какая сегодня погода?» +# заготовленными ответами, а на все остальные вопросы – +# «Вопрос некорректен, попробуйте сформулировать его по-другому». + +while question := input("Задайте вопрос"): + match question.lower(): + case "привет": + print("Привет, чё как ты?") + case "как дела?" | "как дела": + print("Хорошо") + case "какая сегодня погода": + print("Погода на сегодня, не знаю может спросим у Яндекса?") + case _: + print("Вопрос некорректен, попробуйте сформулировать его по-другому") + + diff --git a/Practice/Fedorov/HW_9/9.1.py b/Practice/Fedorov/HW_9/9.1.py new file mode 100644 index 0000000..a2b1a8f --- /dev/null +++ b/Practice/Fedorov/HW_9/9.1.py @@ -0,0 +1,26 @@ +import re +from pathlib import Path + +current_path = str(Path.cwd()) +need_path = current_path.replace("Fedorov\\HW_9", "") + "README.md" +pattern1 = r"git [a-z]{3,}.+" +pattern2 = r"[а-я].+" +commands1 = re.compile(pattern1) +repl_rus_simbols = re.compile(pattern2) +lst = set() +with open(need_path, encoding='utf-8') as myfile: + text = myfile.readline() + while text: + i = commands1.search(text) + if i: + i = i.group(0).lower().replace("\"", "").replace(",", "").replace("(", "") + if len(i) > 30: + m = repl_rus_simbols.search(i) + if m: + i = i.replace(m.group(0), "") + lst.add(i) + text = myfile.readline() + +for i in lst: + if i: + print(i) diff --git a/Practice/Fedorov/HW_9/9.2.py b/Practice/Fedorov/HW_9/9.2.py new file mode 100644 index 0000000..50d30be --- /dev/null +++ b/Practice/Fedorov/HW_9/9.2.py @@ -0,0 +1,26 @@ +import datetime as dt + + +def string_as_date(str_as_date): + return dt.datetime.strptime(str_as_date, "%d.%m.%Y").date() + + +def work_day(start_date, end_date_include, lst_holidays): + start_date = string_as_date(start_date) + end_date = string_as_date(end_date_include) + new_holidays = [string_as_date(i) for i in lst_holidays] + if end_date.weekday() > 4 or end_date in new_holidays: + res = end_date - start_date + else: + res = end_date - start_date + dt.timedelta(days=1) + while start_date != end_date: + if start_date.weekday() > 4: + res -= dt.timedelta(days=1) + elif start_date in new_holidays: + res -= dt.timedelta(days=1) + start_date += dt.timedelta(days=1) + return res + + +holidays = ("01.05.2023", "09.05.2023", "02.07.2023") +print(work_day("30.06.2023", "30.06.2023", holidays)) diff --git a/Practice/Fedorov/HW_9/9.3.py b/Practice/Fedorov/HW_9/9.3.py new file mode 100644 index 0000000..47ed9f7 --- /dev/null +++ b/Practice/Fedorov/HW_9/9.3.py @@ -0,0 +1,25 @@ +import os +import datetime as dt + + +def difference_time(path, minut): + return (dt.datetime.now() - dt.datetime.fromtimestamp(os.path.getctime(path)) > dt.timedelta(minutes=minut)) + + +tfs_path = input("Введите путь") +while True: + for root, dirs, files in os.walk(tfs_path): + for file in files: + file_path = root + f"\\{file}" + if difference_time(file_path, 1): + try: + os.remove(file_path) + except OSError: + print(f"Файл:\n{file_path}\n- не может быть удален") + for folder in dirs: + folder_path = root + f"\\{folder}" + if difference_time(folder_path, 2): + try: + os.rmdir(folder_path) + except OSError: + print(f"Папка:\n{folder_path}\n- не может быть удалена") diff --git a/Practice/Fedorov/HW_9/9.4.py b/Practice/Fedorov/HW_9/9.4.py new file mode 100644 index 0000000..1e1b5c3 --- /dev/null +++ b/Practice/Fedorov/HW_9/9.4.py @@ -0,0 +1,40 @@ +import random +import pickle + +my_dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + +class Human: + def __init__(self, name="", surname="", age="", town="", district="", street=""): + self.name = name if name else self.random_simbols() + self.surname = surname if surname else self.random_simbols() + self.age = age if age else self.random_simbols() + self.town = town if town else self.random_simbols() + self.district = district if district else self.random_simbols() + self.street = street if street else self.random_simbols() + + def about_me(self): + print(f"Имя: {self.name} Фамилия: {self.surname}") + + @staticmethod + def random_simbols(): + res = "" + while len(res) < 5: + res += random.choice(my_dictionary) + return res + + +def human_in(count_human): + lst = [Human() for _ in range(count_human)] + with open("human.data", "wb") as file: + pickle.dump(lst, file, protocol=pickle.HIGHEST_PROTOCOL) + + +def human_out(): + with open("human.data", "rb") as file: + humans = pickle.load(file) + return humans + + +human_in(5) +print(human_out()) diff --git a/Practice/Fedorov/HW_9/human.data b/Practice/Fedorov/HW_9/human.data new file mode 100644 index 0000000..50e5e38 Binary files /dev/null and b/Practice/Fedorov/HW_9/human.data differ diff --git a/Practice/Kisunkina/lec 4/homework4.5.2.py b/Practice/Kisunkina/lec 4/homework4.5.2.py new file mode 100644 index 0000000..db6a462 --- /dev/null +++ b/Practice/Kisunkina/lec 4/homework4.5.2.py @@ -0,0 +1,48 @@ +# Реализовать приложение, загадывающее целое число из заданного пользователем +# диапазона и предлагающее пользователю это число угадать. Отгадывание числа должно +# быть реализовано в цикле: пока пользователь не угадает, или не введет нечисловой символ, +# продолжать опрос. Если пользователь вводит неправильное число, вывести подсказку: +# больше оно или меньше загаданного. + +import random + + +def check(text): + int_input_number = None + text_input = text + while int_input_number is None: + input_number = input(text_input) + if input_number.lstrip("-").isdigit(): + int_input_number = int(input_number) + else: + text_input = "Это не число, введи еще раз!" + return int_input_number + + +x = check("Введите начало диапазона целым числом: ") +y = check("Введите конец диапазона целым числом: ") +rand = None + + +while x == y: + y = int(input(("Значение границы не могут быть равны! Введите конец диапазона " + "другим целым числом: "))) +if x < y: + rand = int(random.randint(x, y)) +elif x > y: + rand = int(random.randint(y, x)) + + +num = check("Вы должны отгадать загаданное число из " + "указанного Вами диапазона. Введите это число: ") +# обработали диапазон и запомнили рандомное значение +# проинициализируем num так, чтобы он точно не был равен рандому + +while num != rand: + if num < rand: + num = int(input("Введенное число меньше загаданного, введите число ещё раз: ")) + elif num > rand: + num = int(input("Введенное число больше загаданного, введите число ещё раз: ")) +print("Ура! Вы угадали!") + + diff --git a/Practice/Kisunkina/lec 4/homework4.5.py b/Practice/Kisunkina/lec 4/homework4.5.py new file mode 100644 index 0000000..ddf0eb7 --- /dev/null +++ b/Practice/Kisunkina/lec 4/homework4.5.py @@ -0,0 +1,39 @@ +# Реализовать приложение, загадывающее целое число из заданного пользователем +# диапазона и предлагающее пользователю это число угадать. Отгадывание числа должно +# быть реализовано в цикле: пока пользователь не угадает, или не введет нечисловой символ, +# продолжать опрос. Если пользователь вводит неправильное число, вывести подсказку: +# больше оно или меньше загаданного. + +import random + + +def check(text): + input_number = input(text) + if input_number.lstrip("-").isdigit(): + return int(input_number) + else: + print("Введенное значение не число") + return check(text) + + +def diapazone(x, y): + if x < y: + return list(range(x, y + 1)) + elif x > y: + return list(range(y, x + 1)) + else: + y = check("Значение границы не могут быть равны! Введите конец диапазона другим целым числом: ") + return diapazone(x, y) + +x = check("Введите начало диапазона целым числом: ") +y = check("Введите конец диапазона целым числом: ") +rand = random.choice(diapazone(x, y)) +num = check("Вы должны отгадать загаданное число из указанного Вами диапазона. Введите это число: ") + + +while num != rand: + if num < rand: + num = check("Введенное число меньше загаданного, введите число ещё раз: ") + else: + num = check("Введенное число больше загаданного, введите число ещё раз: ") +print("Ура! Вы угадали!") diff --git a/Practice/Kisunkina/lec 4/homework4.7.py b/Practice/Kisunkina/lec 4/homework4.7.py new file mode 100644 index 0000000..5a42622 --- /dev/null +++ b/Practice/Kisunkina/lec 4/homework4.7.py @@ -0,0 +1,16 @@ +# Написать декоратор, выводящий "===========" до и после запуска функции. + +def decor_fun(function_to_decorate): + def inner_fun(*args, **kwargs): + print('"==========="') + res = function_to_decorate(*args, **kwargs) + print('"==========="') + return res + return inner_fun + +@decor_fun +def alone(): + print("Я просто функция, для проверки") + + +alone() diff --git a/Practice/Kisunkina/lec 4/homework4.8.py b/Practice/Kisunkina/lec 4/homework4.8.py new file mode 100644 index 0000000..2ae5a94 --- /dev/null +++ b/Practice/Kisunkina/lec 4/homework4.8.py @@ -0,0 +1,28 @@ +# Написать приложение – игру "камень, ножницы, бумага". + +import random + +print("Вы попали в игру 'Камень, ножницы, бумага', Если надоест играть, напишите: хватит") +comp = random.choice(["камень", "ножницы", "бумага"]) + +while (answer := input("Выберете камень, ножницы или бумага: ").lower()) != "хватит": + print(f"Выбор компьютера: {comp}") + if answer == comp: + print("Ничья") + elif answer == "камень": + if comp == "ножницы": + print("Вы выиграли") + else: + print("Вы проиграли") + elif answer == "ножницы": + if comp == "Бумага": + print("Вы выиграли") + else: + print("Вы проиграли") + elif answer == "бумага": + if comp == "камень": + print("Вы выиграли") + else: + print("Вы проиграли") + else: + print("Вы ввели неверное значение, попробуйте ещё") diff --git a/Practice/Kisunkina/lec 5/homework 5.1.py b/Practice/Kisunkina/lec 5/homework 5.1.py new file mode 100644 index 0000000..a7635d8 --- /dev/null +++ b/Practice/Kisunkina/lec 5/homework 5.1.py @@ -0,0 +1,28 @@ +# Реализовать алгоритм сортировки выбором. Алгоритм состоит из следующих шагов: +# найти наименьший элемент в массиве +# поменять местами его и первый элемент в массиве +# найти следующий наименьший элемент в массиве +# и поменять местами его и второй элемент массива +# продолжать это пока весь массив не будет отсортирован +# arr = [0,3,24,2,3,7] +# // здесь реализованный алгоритм +# // на выходе должен получиться список, содержащий [0, 2, 3, 3, 7, 24] + +def sort_arr(arr): + for indx in range(len(arr)): + ost_indx = indx + 1 + min_elem = arr[indx] + min_idx = indx + for i in range(len(arr) - ost_indx): + if arr[ost_indx] < min_elem: + min_elem = arr[ost_indx] + min_idx = ost_indx + ost_indx += 1 + arr[indx], arr[min_idx] = arr[min_idx], arr[indx] + print(f'{arr}') + return arr + + +if __name__ == '__main__': + arr = [0, 3, 24, 2, 3, 7] + sort_arr(arr) diff --git a/Practice/Kisunkina/lec 5/homework 5.2.py b/Practice/Kisunkina/lec 5/homework 5.2.py new file mode 100644 index 0000000..eca79c8 --- /dev/null +++ b/Practice/Kisunkina/lec 5/homework 5.2.py @@ -0,0 +1,16 @@ +# Написать и вызвать функцию, возвращающую первый повторившийся символ в переданном списке. +# Например, для списка [2, 3, 4, 5, 3, 2] функция должна вернуть 3. + +def compare_arg(arr): + arr2 = set() + for elem in arr: + if elem in arr2: + print(f'Первое повторяющееся число {elem}') + return elem + else: + arr2.add(elem) + + +if __name__ == '__main__': + arr = [2, 3, 4, 5, 3, 2] + compare_arg(arr) diff --git a/Practice/Kisunkina/lec 5/homework 5.3.py b/Practice/Kisunkina/lec 5/homework 5.3.py new file mode 100644 index 0000000..ee84220 --- /dev/null +++ b/Practice/Kisunkina/lec 5/homework 5.3.py @@ -0,0 +1,16 @@ +# Найти и заменить некие шаблоны в строке: есть строка с определенного вида форматированием, +# необходимо заменить в этой строке все вхождения шаблонов на их значение из словаря. + + +def zam(text, d): + for key in d: + text = text.replace(key, str(d[key])) + print(f'Раскрою тайну! {text}') + return text + + +if __name__ == '__main__': + text = "Фильм на вечер: ***. Рейтинг: _. Рекомендация на просмотр от /." + print(text) + d = {"***": "Круэлла", "_": "7.6", "/": "75,6% зрителей"} + zam(text, d) diff --git a/Practice/MLoginova/Loginova_10.1.py b/Practice/MLoginova/Loginova_10.1.py new file mode 100644 index 0000000..f9a73ec --- /dev/null +++ b/Practice/MLoginova/Loginova_10.1.py @@ -0,0 +1,15 @@ +# Написать функцию find_primes(end, start), которая ищет все простые числа в диапазоне от заданного числа +# start (по умолчанию 3) до заданного числа end. Далее необходимо: +# Запустить ее три раза последовательно в диапазоне от 3 до 10000, от 10001 до 20000, от 20001 до 30000. +import time +import Loginova_10 + + +if __name__ == "__main__": + data = [(3, 10000), (10001, 20000), (20001, 30000)] + start = time.perf_counter() + for i in range(len(data)): + Loginova_10.find_primes(*data[i]) + print(f'Время вычислений в секундах: {time.perf_counter() - start}') +# Время вычислений c использованием процессов в секундах: 0.030037499964237213 + diff --git a/Practice/MLoginova/Loginova_10.1_multiprocessing.py b/Practice/MLoginova/Loginova_10.1_multiprocessing.py new file mode 100644 index 0000000..81c0f44 --- /dev/null +++ b/Practice/MLoginova/Loginova_10.1_multiprocessing.py @@ -0,0 +1,24 @@ +import multiprocessing +import time +import Loginova_10 + + +if __name__ == "__main__": + + data = [(3, 10000), (10001, 20000), (20001, 30000)] + start = time.perf_counter() + lst = [] + for i in range(len(data)): + pr = multiprocessing.Process(target=Loginova_10.find_primes, args=data[i]) + pr.start() + # Если забыть выполнить start для процессов, то аналогично потокам, мы не направим ОС команду на создание + # процесса + # код вернёт исключение AssertionError: can only join a started process + # дословно может присоединиться только к запущенному процессу + lst.append(pr) + for pr in lst: + pr.join() + # Если забыть выполнить join для процессов, то программа завершит свое выполнение, не дожидаясь завершения + # наших процессов + print(f'Время вычислений c использованием процессов в секундах: {time.perf_counter() - start}') +# Время вычислений c использованием процессов в секундах: 0.03076120000332594 diff --git a/Practice/MLoginova/Loginova_10.1_threading.py b/Practice/MLoginova/Loginova_10.1_threading.py new file mode 100644 index 0000000..f1ae456 --- /dev/null +++ b/Practice/MLoginova/Loginova_10.1_threading.py @@ -0,0 +1,23 @@ +import threading +import time +import Loginova_10 + +if __name__ == "__main__": + data = [(3, 10000), (10001, 20000), (20001, 30000)] + start = time.perf_counter() + threads = [] + for i in range(len(data)): + thr = threading.Thread(target=Loginova_10.find_primes, args=(*data[i],)) + thr.start() + # Если забыть выполнить start для потоков, то мы не направим ОС команду на создание потока, + # код вернёт исключение RuntimeError: cannot join thread before it is started + # дословно невозможно присоединиться к потоку до его запуска + threads.append(thr) + for thr in threads: + thr.join() + # Если забыть выполнить join для потоков, то мы бросили наши len(data) потоков не дождавшись их объединения + # программа завершит свое выполнение, не дожидаясь завершения наших потоков в итоге замеряемое время + # для каждого потока будет неккоректным + print(f'Время вычислений c использованием потоков в секундах: {time.perf_counter() - start}') +# Время вычислений c использованием потоков в секундах: 0.031701300060376525 + diff --git a/Practice/MLoginova/Loginova_10.py b/Practice/MLoginova/Loginova_10.py new file mode 100644 index 0000000..85df219 --- /dev/null +++ b/Practice/MLoginova/Loginova_10.py @@ -0,0 +1,13 @@ +def find_primes(start=3, end=None): + pr_chisla = [] + while start <= end: + k = 2 + sqrt = start ** 0.5 + while k <= sqrt: + if start % k == 0: + break + k += 1 + else: + pr_chisla.append(start) + start += 1 + # print(pr_chisla) diff --git a/Practice/MLoginova/Loginova_12.2.py b/Practice/MLoginova/Loginova_12.2.py new file mode 100644 index 0000000..67e1956 --- /dev/null +++ b/Practice/MLoginova/Loginova_12.2.py @@ -0,0 +1,111 @@ +import sqlite3 +import os + + +def configure_db(conn): + cur = conn.cursor() + + # Создаем таблицу Manufacturers + cur.execute("CREATE TABLE Manufacturers" + " (Manufacturer_id INTEGER PRIMARY KEY AUTOINCREMENT," + " Manufacturer_name CHAR(128) NOT NULL)") + + # Создаем таблицу Products + cur.execute("CREATE TABLE Products" + " (Product_id INTEGER PRIMARY KEY AUTOINCREMENT," + " Product_name CHAR(128) NOT NULL," + " Manufacturer_id INTEGER," + " FOREIGN KEY(Manufacturer_id) REFERENCES Manufacturers(Manufacturer_id))") + + # Создаем таблицу Clients + cur.execute("CREATE TABLE Clients " + " (Client_id INTEGER PRIMARY KEY AUTOINCREMENT," + " Client_name CHAR(128) NOT NULL," + " Client_surname CHAR(128))") + + # Создаем таблицу Purchases + cur.execute("CREATE TABLE Purchases " + " (Purchase_id INTEGER PRIMARY KEY AUTOINCREMENT," + " Product_id INTEGER NOT NULL," + " Client_id INTEGER NOT NULL," + " Purchase_date CHAR(8)," + " FOREIGN KEY(product_id) REFERENCES Products(Product_id)," + " FOREIGN KEY(Client_id) REFERENCES Clients(Client_id))") + +# Добавление записей в таблицу Manufacturers +def insert_manufacturers(conn, name): + cur = conn.cursor() + cur.execute("INSERT INTO Manufacturers (Manufacturer_name)" + " VALUES (:Manufacturer_name)", + {'Manufacturer_name': name}) + conn.commit() + +# Добавление записей в таблицу Products +def insert_products(conn, name, id): + cur = conn.cursor() + cur.execute("INSERT INTO Products (Product_name, Manufacturer_id)" + " VALUES (:Product_name, :Manufacturer_id)", + {'Product_name': name, 'Manufacturer_id': id}) + conn.commit() + +# Добавление записей в таблицу Clients +def insert_clients(conn, name, surname): + cur = conn.cursor() + cur.execute("INSERT INTO Clients (Client_name, Client_surname)" + " VALUES (:Client_name, :Client_surname)", + {'Client_name': name, 'Client_surname': surname}) + conn.commit() + + # Добавление записей в таблицу Purchases +def insert_purchases(conn, product_id, client_id, date_op): + cur = conn.cursor() + cur.execute("INSERT INTO Purchases (Product_id, Client_id, Purchase_date )" + " VALUES (:Product_id, :Client_id, :Purchase_date)", + {'Product_id': product_id, 'Client_id': client_id, 'Purchase_date': date_op}) + conn.commit() + +# Вывод информации о всех товарах с указанием информации о производителе +def show_products_info(conn): + cur = conn.cursor() + cur.execute("SELECT P.Product_name, M.Manufacturer_name" + " FROM Products as P, Manufacturers as M " + " WHERE P. Manufacturer_id = M. Manufacturer_id") + print("Товары и их производители:") + for row in cur.fetchall(): + print(dict(row)) + +# Вывод информации о всех товарах, которые никто не покупал +def show_products_ostatok(conn): + cur = conn.cursor() + cur.row_factory = None + cur.execute("SELECT Pr.Product_id, Pr.Product_name FROM Products as Pr left join Purchases as P " + "on Pr.Product_id = P.Product_id where p.Purchase_id is null") + print("Товары, которые никто не покупал:") + for row in cur: + print(row) + + +if __name__ == "__main__": + db_name = "shop.db" + db_exists = os.path.exists(db_name) + + with (sqlite3.connect(db_name)) as db: + db.row_factory = sqlite3.Row + if not db_exists: + configure_db(db) + + insert_manufacturers(db, "LG") + insert_manufacturers(db, "Samsung") + insert_manufacturers(db, "Haier") + insert_products(db, "Холодильник", 3) + insert_products(db, "Телевизор", 1) + insert_products(db, "Микроволновка", 2) + insert_products(db, "Телефон", 1) + insert_clients(db, "Иван", "Иванов") + insert_clients(db, "Пётр", "Петров") + insert_purchases(db, 1, 1, '15.05.23') + insert_purchases(db, 2, 2, '15.05.23') + + show_products_info(db) + print('/*********************************************************************************************************/') + show_products_ostatok(db) diff --git a/Practice/MLoginova/Loginova_13.2.py b/Practice/MLoginova/Loginova_13.2.py new file mode 100644 index 0000000..3266555 --- /dev/null +++ b/Practice/MLoginova/Loginova_13.2.py @@ -0,0 +1,47 @@ +import mongoengine as me + + +class RegistryUL(me.Document): + inn = me.StringField(max_length=10, required=True) + name_organ = me.StringField(max_length=256, required=True) + type_ownership = me.StringField(max_length=50) + name_owner = me.StringField(max_length=256) + address = me.StringField(max_length=256) + + def __repr__(self): + return (f"ИНН:{self.inn};\n Наименование организации:{self.name_organ};\n" + f"Форма собственности:{self.type_ownership};\n" + f"ФИО владельца:{self.name_owner};\n Адрес:{self.address}.") + + +if __name__ == "__main__": + db_name = 'test' + with (me.connect(db_name)) as conn: + if RegistryUL.objects.count() == 0: + if (k := input("Отсутствуют документы в БД. Заполнить тестовыми данными? (y/n)\n")) == 'y': + org1 = RegistryUL(inn='1234567890', + name_organ='SUN', + type_ownership='ООО', + name_owner='Иванов И.И.', + address='Россия, г.Нижний Новгород, ул. Горького, д.65') + org1.save() + org2 = RegistryUL(inn='1234567891', + name_organ='Оазис', + type_ownership='ОАО', + name_owner='Петров И.И.', + address='Россия, г.Нижний Новгород, ул. Ильниская, д.45') + org2.save() + org3 = RegistryUL(inn='1234567892', + name_organ='Генезис', + type_ownership='ПАО', + name_owner='Сидоров И.И.', + address='Россия, г.Нижний Новгород, ул. Обухова, д.20') + org3.save() + else: + print(f"Документов в базе:{RegistryUL.objects.count()}. Выход") + if RegistryUL.objects.count() != 0: + print(f"Документов в базе:{RegistryUL.objects.count()}.") + input_inn = ' ' + while len(input_inn := input("Введите ИНН ЮЛ(10 символов): ")) != 10: + print(f"Вы ввели ИНН из {len(input_inn)} символов, нужно из 10. Повторите ввод!") + print(f"Информация по ЮЛ по ИНН {input_inn}:\n {RegistryUL.objects.filter(inn=input_inn)}") diff --git a/Practice/MLoginova/Loginova_14.py b/Practice/MLoginova/Loginova_14.py new file mode 100644 index 0000000..aae9727 --- /dev/null +++ b/Practice/MLoginova/Loginova_14.py @@ -0,0 +1,21 @@ +class MyError(Exception): + pass + +class MyFun: + __roman_numbers = {'M': 1000, 'CM': 900, 'D': 500, 'CD': 400, + 'C': 100, 'XC': 90, 'L': 50, 'XL': 40, + 'X': 10, 'IX': 9, 'V': 5, 'IV': 4, 'I': 1} + + def to_roman(self, number): + roman = '' + if not isinstance(number, int) or number not in range(1, 5001): + raise MyError('NonValidInput') + for i, value in self.__roman_numbers.items(): + while number >= value: + roman += i + number -= value + return roman + + +if __name__ == '__main__': + m1 = MyFun() diff --git a/Practice/MLoginova/tests.py b/Practice/MLoginova/tests.py new file mode 100644 index 0000000..100f03d --- /dev/null +++ b/Practice/MLoginova/tests.py @@ -0,0 +1,14 @@ +import pytest +import Loginova_14 + + +class TestMyProv: + _m_test = Loginova_14.MyFun() + + def test_to_roman(self): + assert self._m_test.to_roman(3459) == 'MMMCDLIX' + + @pytest.mark.parametrize("number", ['3459', 5521, -2]) + def test_my_error1(self, number): + with pytest.raises(Loginova_14.MyError): + self._m_test.to_roman(number) diff --git a/Practice/Ozerova/10/10.2.py b/Practice/Ozerova/10/10.2.py new file mode 100644 index 0000000..e01edf0 --- /dev/null +++ b/Practice/Ozerova/10/10.2.py @@ -0,0 +1,30 @@ +import threading + +def fun(x, y): + return x + y + +def add3(arg_new): + for args in arg_new: + x, y = args + res = fun(x, y) + print(f'{x} + {y} = {res}') + +def add_integer(a): + int_thr = threading.Thread(target=add3, args=(a,)) + int_thr.start() + +def add_string(b): + str_thr = threading.Thread(target=add3, args=(b,)) + str_thr.start() + +def add_list(c): + l_thr = threading.Thread(target=add3, args=(c,)) + l_thr.start() + +a = [(1, 2), (3,4)] +b = [('hello', 'bye'), ('Ivan', 'Maria')] +c = [([1, 2], [3, 4]), (['abc'], ['def'])] + +add_integer(a) +add_string(b) +add_list(c) diff --git a/Practice/Ozerova/11/11.2.client.py b/Practice/Ozerova/11/11.2.client.py new file mode 100644 index 0000000..df18c09 --- /dev/null +++ b/Practice/Ozerova/11/11.2.client.py @@ -0,0 +1,22 @@ +import socket +import pickle + +class User: + def __init__(self, name, age): + self.name = name + self.age = age + +def send_user_info(name, age): + user = User(name, age) + data = pickle.dumps(user) + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(('localhost', 12345)) + + s.sendall(data) + s.close() + +if __name__ == '__main__': + name = input('Введите имя пользователя: ') + age = int(input('Введите возраст пользователя: ')) + send_user_info(name, age) diff --git a/Practice/Ozerova/11/11.2.server.py b/Practice/Ozerova/11/11.2.server.py new file mode 100644 index 0000000..a1c5762 --- /dev/null +++ b/Practice/Ozerova/11/11.2.server.py @@ -0,0 +1,30 @@ +import socket +import pickle + +class User: + def __init__(self, name, age): + self.name = name + self.age = age + +def receive_user_info(): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(('localhost', 12345)) + s.listen(5) + + while True: + conn, addr = s.accept() + + data = conn.recv(1024) + + if not data: + break + + user = pickle.loads(data) + + print(f'Имя пользователя: {user.name}') + print(f'Возраст пользователя: {user.age}') + + conn.close() + +if __name__ == '__main__': + receive_user_info() \ No newline at end of file diff --git a/Practice/Ozerova/13/13.1 b/Practice/Ozerova/13/13.1 new file mode 100644 index 0000000..e2c52f7 --- /dev/null +++ b/Practice/Ozerova/13/13.1 @@ -0,0 +1,24 @@ +2 примера: Интернет вещей и Аналитические системы +Интернет вещей: В предметной области имеется огромное количество устройств, +собирающих и передающих данные, NoSQL-подход является более предпочтительным. +Причины: +1. гибкость схемы данных, поскольку данные могут иметь различную структуру, +так как они могут собираться с разных типов устройств. +NoSQL, такие как MongoDB или Cassandra, позволяют хранить данные без строгих +требований к схеме, что позволяет легко и быстро добавлять новые типы данных или изменять существующие. +и 2. горизонтальное масштабирование: здесь важно, чтобы база данных могла масштабироваться горизонтально, +чтобы обрабатывать большой объем данных и обеспечивать высокую производительность. +NoSQL обычно предлагают схему распределенной архитектуры, +что обеспечивает горизонтальное масштабирование и масштабируемость. + +Аналитические системы Big Data: данные имеют большой объем и требуется выполнение сложных +аналитических запросов, NoSQL-подход также является более подходящим. +Причины: +1. гибкость схемы данных - данные могут меняться и иметь различную структуру, поскольку они могут +быть собраны из различных источников данных. NoSQL базы данных позволяют гибко изменять +схему данных и легко добавлять новые типы данных или изменять существующие без ограничений схемы данных. +2. горизонтальное масштабирование: аналитические системы требуют обработки большого объема данных +для выполнения сложных запросов и анализа больших наборов данных. +NoSQL базы данных, такие как Apache HBase или Apache Cassandra, позволяют горизонтальное масштабирование +для обработки большого объема данных и предоставляют высокую производительность. + diff --git a/Practice/Pripisnov/work/my6.1work.py b/Practice/Pripisnov/work/my6.1work.py new file mode 100644 index 0000000..e65340f --- /dev/null +++ b/Practice/Pripisnov/work/my6.1work.py @@ -0,0 +1,50 @@ +class Tank: + def __init__(self, name, health, damage): + self.name = name + self.health = health + self.damage = damage + + def shoot(self, target): + print(f"{self.name} наносит {self.damage} урона {target.name}") + target.health -= self.damage + + +class BattleField: + def __init__(self, width, height): + self.width = width + self.height = height + self.tanks = [] + + def add_tank(self, tank): + self.tanks.append(tank) + print(f"{tank.name} добавлен на поле боя") + + def start_battle(self): + print("Битва началась!") + while len(self.tanks) > 1: + attacker = self.tanks[0] + defender = self.tanks[1] + + attacker.shoot(defender) + + if defender.health <= 0: + print(f"{defender.name} уничтожен!") + self.tanks.remove(defender) + + self.tanks.reverse() + + print(f"{self.tanks[0].name} победил в битве!") + + +# Создание экземпляров классов +tank1 = Tank("Тiger", 100, 20) +tank2 = Tank("Leopard", 150, 15) +tank3 = Tank("Т-34", 120, 25) + +battlefield = BattleField(10, 10) + +battlefield.add_tank(tank1) +battlefield.add_tank(tank2) +battlefield.add_tank(tank3) + +battlefield.start_battle() diff --git a/Practice/Pripisnov/work/my6.2work.py b/Practice/Pripisnov/work/my6.2work.py new file mode 100644 index 0000000..0e5024d --- /dev/null +++ b/Practice/Pripisnov/work/my6.2work.py @@ -0,0 +1,63 @@ +class Duck: + color = "коричневый" # Общий атрибут color для всех экземпляров класса + + def __init__(self, name, weight): + self.name = name + self.weight = weight + + @staticmethod + def quack(): + print("Crack") + + @classmethod + def get_color(cls): + print(f"Цвет утки - {cls.color}") + + def display_info(self): + print(f"Имя: {self.name}, Вес: {self.weight} кг") + + def __repr__(self): + return f"Утка(имя={self.name}, вес={self.weight})" + + def __lt__(self, other): + return self.weight < other.weight + + def __gt__(self, other): + return self.weight > other.weight + + def __eq__(self, other): + return self.weight == other.weight + + def __ne__(self, other): + return self.weight != other.weight + + def __add__(self, other): + new_weight = self.weight + other.weight + return Duck("Дональд Серошейный", new_weight) + + +duck1 = Duck("Серая шейка", 1.5) +duck2 = Duck("Дональд", 2.0) + +# Вызов статического метода +Duck.quack() + +# Вызов классового метода +Duck.get_color() + +# Вызов методов экземпляров +duck1.display_info() +duck2.display_info() + +# Вызов метода __repr__ +print(duck1) + +# Сравнение уток по весу +print(duck1 > duck2) +print(duck1 < duck2) +print(duck1 == duck2) +print(duck1 != duck2) + +# Использование метода __add__ +combined_duck = duck1 + duck2 +combined_duck.display_info() diff --git a/Practice/Pripisnov/work/my6.3work.py b/Practice/Pripisnov/work/my6.3work.py new file mode 100644 index 0000000..bfd8f7e --- /dev/null +++ b/Practice/Pripisnov/work/my6.3work.py @@ -0,0 +1,33 @@ +import os +import tempfile + + +class WrapStrToFile: + def __init__(self): + self.filepath = tempfile.mktemp() + + @property + def content(self): + try: + with open(self.filepath, 'r') as file: + return file.read() + except FileNotFoundError: + return "File doesn't exist" + + @content.setter + def content(self, value): + with open(self.filepath, 'w') as file: + file.write(value) + + @content.deleter + def content(self): + os.remove(self.filepath) + + +wstf = WrapStrToFile() +print(wstf.content) +wstf.content = 'test str' +print(wstf.content) +wstf.content = 'text 2' +print(wstf.content) +del wstf.content diff --git a/Practice/Svetlova/D.Z5.3.1.py b/Practice/Svetlova/D.Z5.3.1.py new file mode 100644 index 0000000..dd05420 --- /dev/null +++ b/Practice/Svetlova/D.Z5.3.1.py @@ -0,0 +1,16 @@ +def zamena(x, y): + for key, value in y.items(): + shablon = f"{{{key}}}" + x = x.replace(shablon, str(value)) + + return x + + + # Пример использования +stroka_shablon = "Здравствуйте, {имя}! познает {имя2} ." +dannie = { + "имя": "Елена", + "имя2": "Pyton" +} +rezult = zamena(stroka_shablon, dannie) +print(rezult) \ No newline at end of file diff --git a/Practice/Svetlova/D.Z6.2.py b/Practice/Svetlova/D.Z6.2.py new file mode 100644 index 0000000..24235a8 --- /dev/null +++ b/Practice/Svetlova/D.Z6.2.py @@ -0,0 +1,125 @@ +class Duck: + color = "yellow" # Общий атрибут цвет для всех экземпляров класса + + def __init__(self, name, weight): + """ + Конструктор класса Duck. + + Args: + name (str): Имя утки. + weight (float): Вес утки. + """ + self.name = name + self.weight = weight + + @staticmethod + def crack(): + """ + Статический метод выводящий звук треска утки. + """ + print("Crack!") + + @classmethod + def get_color(cls): + """ + Классовый метод выводящий цвет уток. + """ + print(f"Цвет уток {cls.color}.") + + def get_name(self): + """ + Метод возвращающий имя утки. + """ + return self.name + + def get_weight(self): + """ + Метод возвращающий вес утки. + """ + return self.weight + + def __lt__(self, other): + """ + Метод сравнения текущей утки с другой по весу (<). + + Args: + other (Duck): Другая утка для сравнения. + + Returns: + bool: Результат сравнения. + """ + return self.weight < other.weight + + def __eq__(self, other): + """ + Метод сравнения текущей утки с другой по весу (==). + + Args: + other (Duck): Другая утка для сравнения. + + Returns: + bool: Результат сравнения. + """ + return self.weight == other.weight + + def __gt__(self, other): + """ + Метод сравнения текущей утки с другой по весу (>). + + Args: + other (Duck): Другая утка для сравнения. + + Returns: + bool: Результат сравнения. + """ + return self.weight > other.weight + + def __ne__(self, other): + """ + Метод сравнения текущей утки с другой по весу (!=). + + Args: + other (Duck): Другая утка для сравнения. + + Returns: + bool: Результат сравнения. + """ + return self.weight != other.weight + + def __add__(self, other): + """ + Метод сложения двух уток, возвращающий утку с суммарным весом. + + Args: + other (Duck): Другая утка для сложения. + + Returns: + Duck: Утка с суммарным весом. + """ + total_weight = self.weight + other.weight + return Duck("Сложение 2 уток", total_weight) + +# Создание экземпляров уток +duck1 = Duck("Утка 1", 1.5) +duck2 = Duck("Утка 2", 2.0) + +# Вызов статического метода +Duck.crack() # Выводит: Crack! + +# Вызов классового метода +Duck.get_color() # Выводит: The color of ducks is yellow. + +# Вызов методов экземпляров +print(duck1.get_name()) # Выводит: Утка 1 +print(duck2.get_weight()) # Выводит: 2.0 + +# Примеры сравнения уток по весу +print(duck1 < duck2) # Выводит: True +print(duck1 == duck2) # Выводит: False +print(duck1 > duck2) # Выводит: False +print(duck1 != duck2) # Выводит: True + +# Пример сложения уток +combined_duck = duck1 + duck2 +print(combined_duck.get_name()) # Выводит: сложение +print(combined_duck.get_weight()) # Выводит: 3.5 \ No newline at end of file diff --git a/Practice/Svetlova/DZ5.3.py b/Practice/Svetlova/DZ5.3.py new file mode 100644 index 0000000..ca28e89 --- /dev/null +++ b/Practice/Svetlova/DZ5.3.py @@ -0,0 +1,16 @@ +def zamena(x, y): + for key, value in y.items(): + shablon = "{" + key + "}" + x = x.replace(shablon, str(value)) + + return x + + +# Пример использования +строка_шаблон = "Здравствуйте, {имя}! познает {имя2} ." +данные = { + "имя": "Елена", + "имя2": "Pyton" +} +результирующая_строка = zamena(строка_шаблон, данные) +print(результирующая_строка) \ No newline at end of file diff --git a/Practice/Svetlova/DZ5.4.py b/Practice/Svetlova/DZ5.4.py new file mode 100644 index 0000000..cccb5ce --- /dev/null +++ b/Practice/Svetlova/DZ5.4.py @@ -0,0 +1,24 @@ +def remove_column(matrix, digit): + num_columns = len(matrix[0]) + indices_to_remove = set() + for i in range(num_columns): + if any(row[i] == digit for row in matrix): + indices_to_remove.add(i) + new_matrix = [] + for row in matrix: + new_row = [row[i] for i in range(num_columns) if i not in indices_to_remove] + new_matrix.append(new_row) + return new_matrix + +matrix = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]] + +new_matrix = remove_column(matrix, 3) + +for row in new_matrix: + print(row) +''' +тип контейнера set для indices_to_remove, что позволяет эффективно проверять наличие индексов во множестве с помощью оператора +in. Это обеспечивает более быструю и оптимальную проверку наличия индексов столбцов для удаления. +''' \ No newline at end of file diff --git a/Practice/Svetlova/DZ5.5.py b/Practice/Svetlova/DZ5.5.py new file mode 100644 index 0000000..bab1f2f --- /dev/null +++ b/Practice/Svetlova/DZ5.5.py @@ -0,0 +1,37 @@ +import os + +def replace_tab_with_spaces_or_tabs(file_path): + """ + Реализует функциональность, которая сворачивает и разворачивает символы табуляции в файле. + На вход передается файл, в котором необходимо заменить все символы табуляции на 4 пробела + или заменить все комбинации из 4 символов пробела на символ табуляции в зависимости от опции, + указанной пользователем. + """ + + if not os.path.isfile(file_path): + print("Файл не существует.") + return + + # Запрашиваем у пользователя выбор опции + option = input("Выберите опцию (1 - замена символов табуляции на 4 пробела, 2 - замена 4 пробелов на символ табуляции): ") + + # Определяем символы для замены в соответствии с выбранной опцией + replacement_chars = ('\t', ' ' * 4) if option == '1' else (' ' * 4, '\t') + + # Открываем файл для чтения и записи + with open(file_path, 'r+') as file: + content = file.read() + + # Заменяем символы табуляции или пробелы в соответствии с выбранной опцией + content = content.replace(*replacement_chars) + + # Возвращаемся в начало файла, очищаем его и записываем измененный контент + file.seek(0) + file.write(content) + file.truncate() + +# Путь к файлу, который нужно обработать +file_path = 'text.txt' + +# Вызываем функцию для замены символов табуляции +replace_tab_with_spaces_or_tabs(file_path) \ No newline at end of file diff --git a/Practice/Svetlova/DZ6.1.py b/Practice/Svetlova/DZ6.1.py new file mode 100644 index 0000000..f2a44c6 --- /dev/null +++ b/Practice/Svetlova/DZ6.1.py @@ -0,0 +1,31 @@ +class Tank: + def __init__(self, name, health, damage): + """ + Конструктор класса Tank. + + Args: + name (str): Имя танка. + health (int): Здоровье танка. + damage (int): Урон, наносимый танком. + """ + self.name = name + self.health = health + self.damage = damage + + def shoot(self, target): + """ + Метод для выстрела танка в цель. + + Args: + target (Tank): Цель для атаки. + """ + target.health -= self.damage + print(f"{self.name} нанес {self.damage} урона по {target.name}. {target.name} имеет {target.health} здоровья.") + + +# Создание экземпляров танков +tank1 = Tank("Танк 1", 100, 20) +tank2 = Tank("Танк 2", 120, 15) + +# Пример использования метода shoot() +tank1.shoot(tank2) diff --git a/Practice/Svetlova/DZ6.3.py b/Practice/Svetlova/DZ6.3.py new file mode 100644 index 0000000..e983f4b --- /dev/null +++ b/Practice/Svetlova/DZ6.3.py @@ -0,0 +1,36 @@ +import tempfile +import os + + +class WrapStrToFile: + def __init__(self): + self._file_path = tempfile.mktemp() + + @property + def content(self): + try: + with open(self._file_path, 'r') as file: + return file.read() + except FileNotFoundError: + return 'Файл еще не существует' + + @content.setter + def content(self, value): + with open(self._file_path, 'w') as file: + file.write(value) + + @content.deleter + def content(self): + if os.path.exists(self._file_path): + os.remove(self._file_path) + + + +wrap = WrapStrToFile() +print(wrap.content) # Вывод: Файл еще не существует + +wrap.content = 'Привет, мир!' +print(wrap.content) # Вывод: Привет, мир! + +del wrap.content +print(wrap.content) # Вывод: Файл еще не существует \ No newline at end of file diff --git a/Practice/Svetlova/DZ7.1.py b/Practice/Svetlova/DZ7.1.py new file mode 100644 index 0000000..4b7104e --- /dev/null +++ b/Practice/Svetlova/DZ7.1.py @@ -0,0 +1,11 @@ +class Man: + def __init__(self, name): + self.name = name + + def solve_task(self): + print("I'm not ready yet") + + +# Пример использования класса +user = Man("Anton") +user.solve_task() \ No newline at end of file diff --git a/Practice/Svetlova/DZ7.2.py b/Practice/Svetlova/DZ7.2.py new file mode 100644 index 0000000..ad93484 --- /dev/null +++ b/Practice/Svetlova/DZ7.2.py @@ -0,0 +1,27 @@ +import time +from random import randint + +class Man: + def __init__(self, name): + self.name = name + + def solve_task(self): + print("Я еще не готов") + +class Pupil(Man): + def solve_task(self): + thinking_time = randint(3, 6) + print(f"{self.name} размышляет...") + time.sleep(thinking_time) + print(f"{self.name} решил/а задачу") + +# Пример использования классов +man = Man("Джон") +man.solve_task() # Вывод: "Я еще не готов" + +pupil = Pupil("Алиса") +pupil.solve_task() +# Вывод: +# "Алиса размышляет..." +# [ожидание случайного времени от 3 до 6 секунд] +# "Алиса решила задачу" \ No newline at end of file diff --git a/Practice/Svetlova/DZ7.3.py b/Practice/Svetlova/DZ7.3.py new file mode 100644 index 0000000..d00d01b --- /dev/null +++ b/Practice/Svetlova/DZ7.3.py @@ -0,0 +1,69 @@ +class ATM: + def __init__(self, cash): + self._cash = cash + + @property + def cash(self): + return self._cash + + def withdraw_cash(self, amount): + if amount <= self._cash: + self._cash -= amount + print(f"Снял {amount} наличными.") + else: + print("Недостаточно наличных средств.") + + def deposit_cash(self, amount): + self._cash += amount + print(f"Внесенная {amount} наличными.") + + def make_payment(self, amount): + self.withdraw_cash(amount) + + +class OnlineATM(ATM): + def make_payment(self, amount): + if amount <= self.cash: + self._cash -= amount + print(f"Произвел онлайн-платеж в размере {amount}.") + else: + print("Недостаточно средств для онлайн-оплаты") + + +def main(): + atm1 = ATM(1000) + atm2 = OnlineATM(2000) + atm3 = ATM(500) + + atm_list = [atm1, atm2, atm3] + + for atm in atm_list: + print(f"ATM Тип: {type(atm).__name__}") + print(f"Доступные наличные: {atm.cash}") + + atm.make_payment(500) + + atm.withdraw_cash(200) + atm.deposit_cash(300) + + print(f"Доступные деньги: {atm.cash}") + print() + + +if __name__ == "__main__": + main() + +'''Вот описание всех изменений, внесенных в код: + +#Класс ATM: + +Добавлено свойство cash, которое предоставляет доступ только для чтения к атрибуту _cash. +Метод make_payment() был добавлен, который вызывает метод withdraw_cash() для совершения платежа. +Класс OnlineATM: + +Метод make_payment() переопределен для класса OnlineATM и заменен на make_online_payment(), который производит онлайн-платеж. +Функция main(): + +Удалена проверка isinstance(atm, OnlineATM) в цикле for. +Вместо этого, вызывается метод make_payment() для всех объектов ATM в списке atm_list, +и в зависимости от типа объекта будет использоваться соответствующая реализация платежа.''' \ No newline at end of file diff --git a/Practice/Svetlova/DZ8.1.py b/Practice/Svetlova/DZ8.1.py new file mode 100644 index 0000000..a28a684 --- /dev/null +++ b/Practice/Svetlova/DZ8.1.py @@ -0,0 +1,31 @@ +class ParagraphIterator: + def __init__(self, text, paragraph_symbol): + self.text = text + self.paragraph_symbol = paragraph_symbol + self.start = 0 + self.end = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.end >= len(self.text): + raise StopIteration + + self.start = self.end + self.end = self.text.find(self.paragraph_symbol, self.start + 1) + if self.end == -1: + self.end = len(self.text) + + paragraph = self.text[self.start:self.end].strip(self.paragraph_symbol) + return paragraph + + +# Пример использования +text = "Это первый параграф.§Это второй параграф.§Это третий параграф." +paragraph_symbol = "§" + +paragraph_iterator = ParagraphIterator(text, paragraph_symbol) + +for paragraph in paragraph_iterator: + print(paragraph) \ No newline at end of file diff --git a/Practice/Svetlova/DZ8.2.py b/Practice/Svetlova/DZ8.2.py new file mode 100644 index 0000000..affc03a --- /dev/null +++ b/Practice/Svetlova/DZ8.2.py @@ -0,0 +1,11 @@ +def read_lines_from_file(filename): + with open(filename, 'r') as file: + for line in file: + yield line.rstrip('\n') + +# Пример использования + +filename = 'example.txt' + +for line in read_lines_from_file(filename): + print(line) \ No newline at end of file diff --git a/Practice/Svetlova/DZ8.3.py b/Practice/Svetlova/DZ8.3.py new file mode 100644 index 0000000..7e746f1 --- /dev/null +++ b/Practice/Svetlova/DZ8.3.py @@ -0,0 +1,16 @@ +import time + +class ExecutionTimer: + def __enter__(self): + self.start_time = time.time() + + def __exit__(self, exc_type, exc_val, exc_tb): + end_time = time.time() + print(f"Execution time: {end_time - self.start_time} seconds") + +# Пример использования + +with ExecutionTimer(): + # Код, время исполнения которого нужно замерить + number_list = range(1000000) + squared_list = [x**2 for x in number_list] \ No newline at end of file diff --git a/Practice/Svetlova/DZ8.4.py b/Practice/Svetlova/DZ8.4.py new file mode 100644 index 0000000..69b05ca --- /dev/null +++ b/Practice/Svetlova/DZ8.4.py @@ -0,0 +1,30 @@ +from itertools import chain, combinations, filterfalse, product + +def merge_arrays(arr1, arr2, arr3): + merged_array = list(chain(arr1, arr2, arr3)) + return merged_array + +def filter_strings(strings): + filtered_strings = list(filterfalse(lambda s: len(s) < 5, strings)) + return filtered_strings + +def generate_combinations(length): + password = 'password' + comb = list(combinations(password, length)) + return comb + +# Пример использования +array1 = [1, 2, 3] +array2 = [4, 5] +array3 = [6, 7] +merged = merge_arrays(array1, array2, array3) +print("Merged array:", merged) + +strings = ['hello', 'i', 'write', 'cool', 'code'] +filtered = filter_strings(strings) +print("Filtered strings:", filtered) + +combinations_list = generate_combinations(4) +print("Combinations:") +for combination in combinations_list: + print(combination) \ No newline at end of file diff --git a/Practice/Svetlova/DZ9.2.py b/Practice/Svetlova/DZ9.2.py new file mode 100644 index 0000000..f1f38d6 --- /dev/null +++ b/Practice/Svetlova/DZ9.2.py @@ -0,0 +1,19 @@ +import datetime + +def count_working_days(start_date, end_date): + days_count = 0 + current_date = start_date + + while current_date <= end_date: + if current_date.weekday() < 5: + days_count += 1 + current_date += datetime.timedelta(days=1) + + return days_count + +# Пример использования +start_date = datetime.date(2023, 1, 1) +end_date = datetime.date(2023, 12, 31) + +working_days = count_working_days(start_date, end_date) +print("Количество рабочих дней:", working_days) \ No newline at end of file diff --git a/Practice/Svetlova/DZ9.3.py b/Practice/Svetlova/DZ9.3.py new file mode 100644 index 0000000..774433a --- /dev/null +++ b/Practice/Svetlova/DZ9.3.py @@ -0,0 +1,23 @@ +import os +import shutil +import time + +folder_path = input("Введите путь до папки: ") + +while True: + for root, dirs, files in os.walk(folder_path): + for file in files: + file_path = os.path.join(root, file) + file_age = time.time() - os.path.getctime(file_path) + + if file_age > 60: # Удаляем файлы, если их возраст больше 1 минуты + os.remove(file_path) + + for dir in dirs: + dir_path = os.path.join(root, dir) + dir_age = time.time() - os.path.getctime(dir_path) + + if dir_age > 120: # Удаляем папки, если их возраст больше 2 минут + shutil.rmtree(dir_path) + + time.sleep(10) # Пауза в 10 секунд между проверками \ No newline at end of file diff --git a/Practice/Svetlova/DZ9.4.py b/Practice/Svetlova/DZ9.4.py new file mode 100644 index 0000000..271d01b --- /dev/null +++ b/Practice/Svetlova/DZ9.4.py @@ -0,0 +1,39 @@ +import pickle +import random + +class Human: + def __init__(self, name, surname, age, residence): + self.name = name + self.surname = surname + self.age = age + self.residence = residence + + def __str__(self): + return f"{self.name} {self.surname}, {self.age} лет/года, живет в {self.residence}" + +def create_humans(num_instances): + first_names = ["John", "Alice", "Michael", "Emily", "David", "Olivia"] + last_names = ["Smith", "Johnson", "Brown", "Lee", "Wilson"] + residences = ["New York", "Los Angeles", "Chicago", "San Francisco", "Seattle"] + + humans = [] + for _ in range(num_instances): + name = random.choice(first_names) + surname = random.choice(last_names) + age = random.randint(18, 60) + residence = random.choice(residences) + human = Human(name, surname, age, residence) + humans.append(human) + + with open("human.data", "wb") as file: + pickle.dump(humans, file) + +def read_humans(): + with open("human.data", "rb") as file: + humans = pickle.load(file) + for human in humans: + print(human) + +if __name__ == "__main__": + create_humans(5) # Создаем 5 экземпляров Human и сохраняем их в файл + read_humans() # Читаем файл и выводим содержимое на печать \ No newline at end of file diff --git a/Practice/Tanacheva/task9.1.py b/Practice/Tanacheva/task9.1.py new file mode 100644 index 0000000..da3f9dc --- /dev/null +++ b/Practice/Tanacheva/task9.1.py @@ -0,0 +1,27 @@ +class Paragragh: + + def __init__(self, text, symbol): + self._i = 0 + self._text = text + self.symbol = symbol + + def __iter__(self): + return self + + def __next__(self): + res = "" + if self._i > len(self._text)-1: + raise StopIteration + while self._text[self._i] != self.symbol: + res += self._text[self._i] + self._i += 1 + if self._i >= len(self._text): + break + else: + self._i += 1 + return res + + +text1 = "gsgs;dgssgsgssg;ssdgs;dsdgdsgfd; ; dbd" +for i in Paragragh(text1, ";"): + print(i) diff --git a/Practice/Tanacheva/task9.2.py b/Practice/Tanacheva/task9.2.py new file mode 100644 index 0000000..acde13a --- /dev/null +++ b/Practice/Tanacheva/task9.2.py @@ -0,0 +1,8 @@ +def myfilereader(filepath): + with open(filepath, "r") as f: + for i in f: + yield i + + +for i in myfilereader("1.txt"): + print(i) diff --git a/Practice/Tanacheva/task9.3.py b/Practice/Tanacheva/task9.3.py new file mode 100644 index 0000000..ddbb18b --- /dev/null +++ b/Practice/Tanacheva/task9.3.py @@ -0,0 +1,15 @@ +import time + + +class TestManager: + + def __enter__(self): + self.start_time = time.time() + + def __exit__(self, exc_type, exc_val, exc_tb): + print(f"Время исполнения функции: {time.time() - self.start_time}") + + +with TestManager(): + for i in range(100000): + print(i) diff --git a/Useful/for_lec17/async_example.py b/Useful/for_lec17/async_example.py new file mode 100644 index 0000000..5b43757 --- /dev/null +++ b/Useful/for_lec17/async_example.py @@ -0,0 +1,41 @@ +import asyncio + +res = 0 + + +# Производим вычисления +async def calc_fun(num): + global res + while num >= 0: + print(num) + if num % 10 == 0: + res = num + num -= 1 + await asyncio.sleep(0.1) + + +# Сообщаем о статусе вычислений +async def status_fun(): + global res + prev_res = 0 + while res > 0: + if res != prev_res: + print(f'{res} numbers remain') + prev_res = res + await asyncio.sleep(0.1) + + +# if __name__ == '__main__': +# ev_loop = asyncio.get_event_loop() +# tasks = [ev_loop.create_task(calc_fun(10)), ev_loop.create_task(status_fun())] +# futures = asyncio.wait(tasks) +# ev_loop.run_until_complete(futures) +# ev_loop.close() + + +async def main(): + tasks = [asyncio.create_task(calc_fun(100)), asyncio.create_task(status_fun())] + await asyncio.gather(*tasks) + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/Useful/for_lec17/condition_example.py b/Useful/for_lec17/condition_example.py new file mode 100644 index 0000000..fcf3b19 --- /dev/null +++ b/Useful/for_lec17/condition_example.py @@ -0,0 +1,23 @@ +# В одном потоке заполняем список, в другом - выводим длину этого списка +from threading import Thread, Condition + +lst = [] + + +def print_len(my_cv): + global lst + with my_cv: + my_cv.wait_for(lambda: 'stop' in lst) + lst.remove('stop') + print(f'length of {lst} is {len(lst)}') + + +if __name__ == '__main__': + cv = Condition() + t = Thread(target=print_len, args=(cv,)) + t.start() + while 'stop' not in lst: + lst.append(input('Enter: ')) + with cv: + cv.notify() + t.join() diff --git a/Useful/for_lec17/event_example.py b/Useful/for_lec17/event_example.py new file mode 100644 index 0000000..2c196a7 --- /dev/null +++ b/Useful/for_lec17/event_example.py @@ -0,0 +1,23 @@ +# В одном потоке заполняем список, в другом - выводим длину этого списка +from threading import Thread, Event + +lst = [] + + +def print_len(my_ev): + global lst + if not my_ev.is_set(): + print('Doing some stuff') + my_ev.wait() + lst.remove('stop') + print(f'length of {lst} is {len(lst)}') + + +if __name__ == '__main__': + ev = Event() # is_set() == False, by default (т.е. ресурс занят) + t = Thread(target=print_len, args=(ev,)) + t.start() + while 'stop' not in lst: + lst.append(input('Enter: ')) + ev.set() + t.join() diff --git a/Useful/for_lec17/file.log b/Useful/for_lec17/file.log new file mode 100644 index 0000000..e02d4d0 --- /dev/null +++ b/Useful/for_lec17/file.log @@ -0,0 +1,2 @@ +2022-08-03 16:21:41,352-INFO-This will get logged +2022-08-03 16:22:40,769-INFO- diff --git a/Useful/for_lec17/infile.txt b/Useful/for_lec17/infile.txt new file mode 100644 index 0000000..822b107 --- /dev/null +++ b/Useful/for_lec17/infile.txt @@ -0,0 +1,78 @@ +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e +9507774534 9507774535 30 t 8 9 4 hf 89 8 0 0 9 e 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d +9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9503334534 9505554535 10 7 6 d 9 wq 7 6 d 9 wq 7 6 d \ No newline at end of file diff --git a/Useful/for_lec17/log_example.py b/Useful/for_lec17/log_example.py new file mode 100644 index 0000000..b1c5b3c --- /dev/null +++ b/Useful/for_lec17/log_example.py @@ -0,0 +1,9 @@ +# Больше примеров здесь: https://webdevblog.ru/logging-v-python/ +import logging + +s_handler = logging.StreamHandler() +f_handler = logging.FileHandler('file.log') +logging.basicConfig(format='%(asctime)s-%(levelname)s-%(message)s', + level=logging.INFO, + handlers=(s_handler, f_handler)) +logging.info('Полезная информация') \ No newline at end of file diff --git a/Useful/for_lec17/no_lock_example.py b/Useful/for_lec17/no_lock_example.py new file mode 100644 index 0000000..b7664c1 --- /dev/null +++ b/Useful/for_lec17/no_lock_example.py @@ -0,0 +1,31 @@ +# Два потока запрашивают и выводят координаты точки на плоскости +from threading import Thread +import time + + +class Base: + x = 0 + y = 0 + + +def print_fun(): + i = 0 + while i < 2: + Base.x = input("2x: ") + Base.y = input("2y: ") + print(f'Thread 2: Base.x = {Base.x}, Base.y = {Base.y}') + i += 1 + time.sleep(1) + + +if __name__ == '__main__': + t = Thread(target=print_fun) + t.start() + i = 0 + while i < 2: + Base.x = input("1x: ") + Base.y = input("1y: ") + print(f'Thread 1: Base.x = {Base.x}, Base.y = {Base.y}') + i += 1 + time.sleep(1) + t.join() diff --git a/Useful/for_lec17/outfile.txt b/Useful/for_lec17/outfile.txt new file mode 100644 index 0000000..8d77d8c --- /dev/null +++ b/Useful/for_lec17/outfile.txt @@ -0,0 +1 @@ +90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90397776589378917156, 90397776608394466225, 900, 64, 81, 16, 7921, 64, 0, 0, 81, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 90313367265116997156, 90355567017859066225, 100, 49, 36, 81, 49, 36, 81, 49, 36, \ No newline at end of file diff --git a/Useful/for_lec17/pool_example.py b/Useful/for_lec17/pool_example.py new file mode 100644 index 0000000..12dd165 --- /dev/null +++ b/Useful/for_lec17/pool_example.py @@ -0,0 +1,18 @@ +from multiprocessing import Pool +import time +import os + + +lst = [] + +def cube(x): + lst.append(x) + print(f"This process {os.getpid()} processed values {lst}") + time.sleep(2) + return x**3 + +if __name__ == '__main__': + pool = Pool(processes=5) + res = pool.map(cube, range(1,7)) + # res = pool.starmap, если в функцию нужно передать несколько аргументов + print(res) diff --git a/Useful/for_lec17/python_mp_pool.pdf b/Useful/for_lec17/python_mp_pool.pdf new file mode 100644 index 0000000..fb1f53f Binary files /dev/null and b/Useful/for_lec17/python_mp_pool.pdf differ diff --git a/Useful/for_lec17/queue_example.py b/Useful/for_lec17/queue_example.py new file mode 100644 index 0000000..a8307c1 --- /dev/null +++ b/Useful/for_lec17/queue_example.py @@ -0,0 +1,40 @@ +import threading +import queue +import time + + +start = time.perf_counter() + +q = queue.Queue() + + +def worker(): # функция выполняемая в дочернем потоке + with open('outfile.txt', 'w') as fout: + item = '0' + while item.isdigit(): + item = q.get() # ожидаем появление элемента в очереди + print(f'get: {item = }') + if item.isdigit(): + fout.write(f'{int(item) ** 2}, ') + print('task_done') + q.task_done() # уведомляем очередь о завершении обработки + + +t = threading.Thread(target=worker) +t.start() + +with open('infile.txt') as fin: + for line in fin: + print(f'main: line: {line}') + items = line.split() + for each in items: + print(f'main: each: {each}') + if each.isdigit(): + q.put(each) # добавляем элемент в очередь и ничего не ждем, + q.join() # ожидаем обработки элементов в очереди + q.put('stop') # добавляем элемент в очередь и ничего не ждем, + q.join() # ожидаем обработки элементов в очереди + +t.join() + +print('Total time: {}'.format(time.perf_counter() - start)) \ No newline at end of file diff --git a/Useful/for_lec17/rlock_example.py b/Useful/for_lec17/rlock_example.py new file mode 100644 index 0000000..84a8fe6 --- /dev/null +++ b/Useful/for_lec17/rlock_example.py @@ -0,0 +1,35 @@ +# Два потока запрашивают и выводят координаты точки на плоскости +from threading import Thread, RLock +import time + + +class Base: + x = 0 + y = 0 + + +def print_fun(my_lock): + i = 0 + while i < 2: + with my_lock: + Base.x = input("2x: ") + Base.y = input("2y: ") + print(f'Thread 2: Base.x = {Base.x}, Base.y = {Base.y}') + i += 1 + time.sleep(1) + + +if __name__ == '__main__': + lock = RLock() + t = Thread(target=print_fun, args=(lock,)) + t.start() + i = 0 + while i < 2: + with lock: + Base.x = input("1x: ") + Base.y = input("1y: ") + print(f'Thread 1: Base.x = {Base.x}, Base.y = {Base.y}') + i += 1 + time.sleep(1) + t.join() + \ No newline at end of file diff --git a/Useful/for_lec18/cherrypy_example_1.py b/Useful/for_lec18/cherrypy_example_1.py new file mode 100644 index 0000000..89054b8 --- /dev/null +++ b/Useful/for_lec18/cherrypy_example_1.py @@ -0,0 +1,13 @@ +import cherrypy + + +class HelloWorld: + + @cherrypy.expose + def index(self): + return 'This is not easy!' + + +if __name__ == '__main__': + cherrypy.config.update({'server.socket_port': 8099}) + cherrypy.quickstart(HelloWorld()) diff --git a/Useful/for_lec18/cherrypy_example_2.py b/Useful/for_lec18/cherrypy_example_2.py new file mode 100644 index 0000000..f18637d --- /dev/null +++ b/Useful/for_lec18/cherrypy_example_2.py @@ -0,0 +1,17 @@ +import cherrypy + + +class Hello: + @cherrypy.expose + def index(self): + with open('index.html', 'r') as f: + s = f.read() + return s.replace(r'{%_%}', 'name') + + @cherrypy.expose + def hello(self, name): + return f'Hello, {name}' + + +if __name__ == '__main__': + cherrypy.quickstart(Hello(), '/') \ No newline at end of file diff --git a/Useful/for_lec18/class_tcp_client.py b/Useful/for_lec18/class_tcp_client.py new file mode 100644 index 0000000..e4d7476 --- /dev/null +++ b/Useful/for_lec18/class_tcp_client.py @@ -0,0 +1,26 @@ +import socket +import random +import time + + +class TcpClient: + def __init__(self, host, port, name): + self.host = host + self.port = port + self.name = name + self._socket = None + + def run(self): + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.connect((self.host, self.port)) + time.sleep(3) + self._socket.send(self.name.encode()) + data = self._socket.recv(1024) + print(f'Received: {data.decode()}') + self._socket.close() + + +if __name__ == '__main__': + name = 'Python client ' + str(random.randint(1, 1000)) + myclient = TcpClient(host='127.0.0.1', port=5555, name=name) + myclient.run() \ No newline at end of file diff --git a/Useful/for_lec18/class_tcp_server.py b/Useful/for_lec18/class_tcp_server.py new file mode 100644 index 0000000..f0be945 --- /dev/null +++ b/Useful/for_lec18/class_tcp_server.py @@ -0,0 +1,51 @@ +import threading +import socket + + +class ClientThread(threading.Thread): + def __init__(self, conn, addr): + super().__init__() + self._connection = conn + self._address = addr + + def run(self): + print('Connection from address {}'.format(self._address)) + data = self._connection.recv(1024) + print('Received {}'.format(data.decode())) + self._connection.send(data) + self._connection.close() + print('Closed connection from {}'.format(self._address)) + + +class TcpServer: + def __init__(self, host, port): + self.host = host + self.port = port + self._socket = None + self._running = False + + def run(self): + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._socket.bind((self.host, self.port)) + self._socket.listen(5) + self._running = True + + print('Server is up') + while self._running: + conn, addr = self._socket.accept() + ClientThread(conn, addr).start() + + def stop(self): + self._running = False + self._socket.close() + print('Server is down') + + +if __name__ == '__main__': + srv = TcpServer(host='127.0.0.1', port=5555) + try: + srv.run() + except KeyboardInterrupt: + srv.stop() + diff --git a/Useful/for_lec18/file_task_example/create_files.py b/Useful/for_lec18/file_task_example/create_files.py new file mode 100644 index 0000000..21ca6c0 --- /dev/null +++ b/Useful/for_lec18/file_task_example/create_files.py @@ -0,0 +1,9 @@ +import random + + + +for i in range(50): + name = f"file_{i}" + with open(name, "w") as f: + f.write(str(random.randint(1, 1000))) + diff --git a/Useful/for_lec18/file_task_example/task.py b/Useful/for_lec18/file_task_example/task.py new file mode 100644 index 0000000..2fb0110 --- /dev/null +++ b/Useful/for_lec18/file_task_example/task.py @@ -0,0 +1,37 @@ +import multiprocessing as mp +import math +import os + + +def file_handler(fname_lst): + lst = [] + for fname in fname_lst: + with open(fname) as f: + s = f.read().strip() + if (i := int(s)) % 10 == 0: + lst.append(i) + print(lst) + + +if __name__ == "__main__": + fname_lst = [] + for fname in os.listdir('.'): + if fname.startswith("file"): + fname_lst.append(fname) + + + num_of_proc = os.cpu_count() - 1 + process_lst = [] + num_per_proc = math.ceil(len(fname_lst) / num_of_proc) + start = 0 + stop = num_per_proc + for i in range(num_of_proc): + slice = fname_lst[start:stop] + start = stop + stop += num_per_proc + p = mp.Process(target=file_handler, args=(slice,)) + p.start() + process_lst.append(p) + + for p in process_lst: + p.join() diff --git a/Useful/for_lec18/http_codes.jpg b/Useful/for_lec18/http_codes.jpg new file mode 100644 index 0000000..b4eff78 Binary files /dev/null and b/Useful/for_lec18/http_codes.jpg differ diff --git a/Useful/for_lec18/index.html b/Useful/for_lec18/index.html new file mode 100644 index 0000000..f96b633 --- /dev/null +++ b/Useful/for_lec18/index.html @@ -0,0 +1,10 @@ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/Useful/for_lec18/mail_sender.py b/Useful/for_lec18/mail_sender.py new file mode 100644 index 0000000..14e755a --- /dev/null +++ b/Useful/for_lec18/mail_sender.py @@ -0,0 +1,20 @@ +from smtplib import SMTP_SSL +from email.mime.text import MIMEText + + +def send(message): + sender = 'python.course@mail.ru' + targets = ['orlov.soft.company@gmail.com'] + + msg = MIMEText(message) + msg['Subject'] = 'Simple subject' + msg['From'] = sender + msg['To'] = ', '.join(targets) + + server = SMTP_SSL('smtp.mail.ru', 465) + server.login(sender, 'CVul9R2wTuFbdgomGjGK') + server.sendmail(sender, targets, msg.as_string()) + server.quit() + + +send("Привет2") diff --git a/Useful/for_lec18/myhttpserver.py b/Useful/for_lec18/myhttpserver.py new file mode 100644 index 0000000..e3b3978 --- /dev/null +++ b/Useful/for_lec18/myhttpserver.py @@ -0,0 +1,19 @@ +from http.server import BaseHTTPRequestHandler, HTTPServer + + +class MyHandler(BaseHTTPRequestHandler): + # обработчик GET запросов + def do_GET(self): + self.send_response(200) # OK + self.send_header('Content-type', 'text/html') + self.end_headers() + # собственно html сообщение + self.wfile.write('

Hello World!

'.encode()) + + +if __name__ == '__main__': + port = 8080 + server = HTTPServer(('127.0.0.1', port), MyHandler) + print('Started HTTP server on port: {}'.format(port)) + # бесконечно ожидаем входящие http запросы + server.serve_forever() \ No newline at end of file diff --git a/Useful/for_lec18/pool_example.py b/Useful/for_lec18/pool_example.py new file mode 100644 index 0000000..21a186b --- /dev/null +++ b/Useful/for_lec18/pool_example.py @@ -0,0 +1,20 @@ +from multiprocessing import Pool +import time +import os + + +lst = [] + + +def cube(x): + lst.append(x) + print(f"This process {os.getpid()} processed values {lst}") + time.sleep(2) + return x**3 + + +if __name__ == '__main__': + pool = Pool(processes=5) + res = pool.map(cube, range(1,7)) + # res = pool.starmap, если в функцию нужно передать несколько аргументов + print(res) diff --git a/Useful/for_lec18/ports_acqusition.txt b/Useful/for_lec18/ports_acqusition.txt new file mode 100644 index 0000000..d38556c --- /dev/null +++ b/Useful/for_lec18/ports_acqusition.txt @@ -0,0 +1,12 @@ +TCP +->*127.0.0.1:12345* +127.0.0.1:59830->127.0.0.1:12345 + +127.0.0.1:59830<-127.0.0.1:55555 +127.0.0.1:59830->127.0.0.1:55555 + +UDP +->*127.0.0.1:12345* +127.0.0.1:59830->127.0.0.1:12345 + +127.0.0.1:59830<-127.0.0.1:12345 \ No newline at end of file diff --git a/Useful/for_lec18/re_temp_example.py b/Useful/for_lec18/re_temp_example.py new file mode 100644 index 0000000..b573368 --- /dev/null +++ b/Useful/for_lec18/re_temp_example.py @@ -0,0 +1,12 @@ +from urllib import request +import re + + +req = request.Request('https://yandex.ru/pogoda/nizhny-novgorod?utm_source=home&utm_medium=web&utm_campaign=informer&utm_content=main_informer&utm_term=title&lat=56.326887&lon=44.005986') +response = request.urlopen(req) +web_page = response.read().decode() +print(web_page) + +s = re.compile(r'"Текущая температура ([+|−]?\d+)') +res = re.findall(s, web_page) +print(res) diff --git a/Useful/for_lec18/tcp_client.py b/Useful/for_lec18/tcp_client.py new file mode 100644 index 0000000..82b7244 --- /dev/null +++ b/Useful/for_lec18/tcp_client.py @@ -0,0 +1,12 @@ +import socket +import pickle +import user + + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +host = '127.0.0.1' +port = 12345 +s.connect((host, port)) # подключаемся к серверу +print(pickle.loads(s.recv(1024))) # получаем и выводим данные, полученные от сервера +s.close() diff --git a/Useful/for_lec18/tcp_client1.py b/Useful/for_lec18/tcp_client1.py new file mode 100644 index 0000000..d4bd795 --- /dev/null +++ b/Useful/for_lec18/tcp_client1.py @@ -0,0 +1,13 @@ +import socket + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +host = '127.0.0.1' +port = 12345 +s.connect((host, port)) # подключаемся к серверу +d = s.recv(1024) # получаем данные от сервера (1024 байта - размер буфера для данных) +while d: + print(d.decode()) + d = s.recv(1024) +# преобразуем данные из байтового представления в строковое и выводим +# (преобразование из utf-8 в ascii) +s.close() diff --git a/Useful/for_lec18/tcp_server.py b/Useful/for_lec18/tcp_server.py new file mode 100644 index 0000000..0d080a0 --- /dev/null +++ b/Useful/for_lec18/tcp_server.py @@ -0,0 +1,21 @@ +import socket +import pickle +import user + + +a = user.User('Ivan', 30) + +# 1-й параметр - семейство адресов, с которыми будет работать сокет +# AF_INET соотвествует адресам IPv4 +# 2-й параметр - протокол транспортного уровня +# SOCK_STREAM соотвествует протоколу TCP +with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + host = '127.0.0.1' + port = 12345 + s.bind((host, port)) + s.listen(5) # Открываем порт на сервере (не более 5 клиентов одновременно) + while True: + conn, addr = s.accept() + with conn: + print('Server got connection from {}'.format(addr)) + conn.send(pickle.dumps(a)) diff --git a/Useful/for_lec18/tcp_server1.py b/Useful/for_lec18/tcp_server1.py new file mode 100644 index 0000000..6dfa1d9 --- /dev/null +++ b/Useful/for_lec18/tcp_server1.py @@ -0,0 +1,18 @@ +import socket + +# 1-й параметр - семейство адресов, с которыми будет работать сокет +# AF_INET соответствует адресам IPv4 +# 2-й параметр - протокол транспортного уровня +# SOCK_STREAM соотвествует протоколу TCP +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +host = '127.0.0.1' # '127.0.0.1' соответствует хосту, на котором запускается скрипт +port = 12345 +s.bind((host, port)) +s.listen(5) # Открываем порт на сервере (не более 5 клиентов одновременно) +while True: + conn, addr = s.accept() + print('Server got connection from {}'.format(addr)) + # Преобразуем строку в набор байтов (ascii в utf-8) и отправляем + conn.send('Thank you for the connection'.encode()) + conn.close() +s.close() diff --git a/Useful/for_lec18/udp_client.py b/Useful/for_lec18/udp_client.py new file mode 100644 index 0000000..8d4b355 --- /dev/null +++ b/Useful/for_lec18/udp_client.py @@ -0,0 +1,12 @@ +import socket + +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +host = '127.0.0.1' +port = 12345 +# отправляем сообщение серверу без установки соединения +s.sendto('client data'.encode(), (host, port)) +# получаем ответ от сервера +data, addr = s.recvfrom(1024) +print(data.decode()) +s.close() \ No newline at end of file diff --git a/Useful/for_lec18/udp_client_encryption.py b/Useful/for_lec18/udp_client_encryption.py new file mode 100644 index 0000000..3a7df8c --- /dev/null +++ b/Useful/for_lec18/udp_client_encryption.py @@ -0,0 +1,19 @@ +import socket + + +def encrypt(string): + res = "" + for x in string: + res += str(ord(x)) + ' ' + return res + + +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +host = '127.0.0.1' +port = 12345 +# отправляем сообщение серверу без установки соединения +s.sendto(encrypt('hello world').encode(), (host, port)) +# получаем ответ от сервера +data, addr = s.recvfrom(1024) +print(data.decode()) +s.close() diff --git a/Useful/for_lec18/udp_server.py b/Useful/for_lec18/udp_server.py new file mode 100644 index 0000000..b48d182 --- /dev/null +++ b/Useful/for_lec18/udp_server.py @@ -0,0 +1,14 @@ +import socket + +# AF_INET соотвествует адресам IPv4 +# SOCK_DGRAM соотвествует протоколу UDP +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +host = '127.0.0.1' +port = 12345 +s.bind((host, port)) +while True: + data, addr = s.recvfrom(1024) + print('Server got data from client: {}'.format(data.decode())) + s.sendto('Thank you for the data'.encode(), addr) +s.close() \ No newline at end of file diff --git a/Useful/for_lec18/udp_server_decryption.py b/Useful/for_lec18/udp_server_decryption.py new file mode 100644 index 0000000..1c640a8 --- /dev/null +++ b/Useful/for_lec18/udp_server_decryption.py @@ -0,0 +1,26 @@ +import socket + + +def decrypt(string): + res = "" + for x in string.split(' '): + if x.isdigit(): + res += chr(int(x)) + else: + res += x + return res + + +# AF_INET соответствует адресам IPv4 +# SOCK_DGRAM соответствует протоколу UDP +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +host = '127.0.0.1' +port = 12345 +s.bind((host, port)) +while True: + data, addr = s.recvfrom(1024) # размер буфера для данных – 1024 байта + res = data.decode() + print(f"{res}") + print(f'Server got data from client: {decrypt(res)}') + s.sendto('Thank you for the data'.encode(), addr) +# s.close() diff --git a/Useful/for_lec18/urllib_example.py b/Useful/for_lec18/urllib_example.py new file mode 100644 index 0000000..d0b542e --- /dev/null +++ b/Useful/for_lec18/urllib_example.py @@ -0,0 +1,11 @@ +from urllib import request +import re + + +req = request.Request('https://yandex.ru/pogoda/nizhny-novgorod?lat=56.326887&lon=44.005986') +response = request.urlopen(req) +web_page = response.read().decode() + +s = re.compile(r'Текущая температура([+|-]\d+)') +res = re.findall(s, web_page) +print(res) diff --git a/Useful/for_lec18/user.py b/Useful/for_lec18/user.py new file mode 100644 index 0000000..d3c8dc6 --- /dev/null +++ b/Useful/for_lec18/user.py @@ -0,0 +1,6 @@ +class User: + def __init__(self, name, age): + self.name = name + self.age = age + def __repr__(self): + return 'User: name={}, age={}'.format(self.name, self.age) diff --git a/Useful/for_lec18/xmlrpc_client.py b/Useful/for_lec18/xmlrpc_client.py new file mode 100644 index 0000000..393f93e --- /dev/null +++ b/Useful/for_lec18/xmlrpc_client.py @@ -0,0 +1,5 @@ +import xmlrpc.client + +proxy = xmlrpc.client.ServerProxy("http://localhost:8000/") +print(f"3 is even: {proxy.is_even(3)}") +print(f"100 is even: {proxy.is_even(100)}") diff --git a/Useful/for_lec18/xmlrpc_server.py b/Useful/for_lec18/xmlrpc_server.py new file mode 100644 index 0000000..3028d34 --- /dev/null +++ b/Useful/for_lec18/xmlrpc_server.py @@ -0,0 +1,12 @@ +from xmlrpc.server import SimpleXMLRPCServer + + +def is_even(n): + return n % 2 == 0 + + +if __name__ == '__main__': + server = SimpleXMLRPCServer(("127.0.0.1", 8000)) + print("Listening on port 8000...") + server.register_function(is_even, "is_even") + server.serve_forever() diff --git "a/Useful/for_lec18/\320\274\320\276\320\264\320\265\320\273\320\270_osi_\320\270_tcp_ip.png" "b/Useful/for_lec18/\320\274\320\276\320\264\320\265\320\273\320\270_osi_\320\270_tcp_ip.png" new file mode 100644 index 0000000..f2347b3 Binary files /dev/null and "b/Useful/for_lec18/\320\274\320\276\320\264\320\265\320\273\320\270_osi_\320\270_tcp_ip.png" differ diff --git a/Useful/for_lec19/check_sqlalchemy.py b/Useful/for_lec19/check_sqlalchemy.py new file mode 100644 index 0000000..5ba50ff --- /dev/null +++ b/Useful/for_lec19/check_sqlalchemy.py @@ -0,0 +1,77 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Integer, String +from sqlalchemy.schema import CreateTable +from sqlalchemy.orm import sessionmaker + + +Base = declarative_base() + +# Создаем базу данных в памяти (без файла) +engine = create_engine('sqlite://') +print('База данных создана') + +# Создаем класс, отображающий таблицу +class User(Base): + __tablename__ = 'users' + + id = Column(Integer, primary_key=True) + name = Column(String) + fullname = Column(String) + password = Column(String) + + def __repr__(self): + return "".format( + self.name, self.fullname, self.password) + +# Создаем схему +Base.metadata.create_all(engine) +print(CreateTable(User.__table__).compile(engine)) +print('Таблица создана') + +# Открываем сессию +Session = sessionmaker(bind=engine) +session = Session() +print('Сессия открыта') + +# Создаем объект отображаемого класса +ed_user = User(name='ed', fullname='Ed jones', password='edpassword') + +# Добавляем новый объект в базу +session.add(ed_user) +session.commit() +print('Объект добавлен') + +# Проверяем, что получилось +print(session.query(User).filter_by(name='ed').first()) + +# Добавляем несколько объектов в базу +session.add_all([ + User(name='wendy', fullname='Wendy Williams', password='pwd'), + User(name='mary', fullname='Mary Contrary', password='qwerty'), + User(name='fred', fullname='Fred Flinstone', password='123')]) +session.commit() +print('Объекты добавлены') + +# Проверяем, что получилось +print('Объектов User в базе: {}'.format(session.query(User).count())) +print(session.query(User).all()) + +# Изменяем запись +ed = session.query(User).filter_by(name='ed').first() +ed.password = 'edsnewpassword' +session.add(ed) +session.commit() + +# Проверяем, что получилось +#print(session.query(User).filter_by(name='ed').first()) +print('Объектов User в базе: {}'.format(session.query(User).count())) +print(session.query(User).all()) + +# Удаляем запись +session.delete(ed) +session.commit() + +# Проверяем, что получилось +print('Объектов User в базе: {}'.format(session.query(User).count())) +print(session.query(User).all()) diff --git a/Useful/for_lec19/check_sqlite.py b/Useful/for_lec19/check_sqlite.py new file mode 100644 index 0000000..f817058 --- /dev/null +++ b/Useful/for_lec19/check_sqlite.py @@ -0,0 +1,94 @@ +import sqlite3 + + +# Подключаемся к базе данных +# Файл базы данных (если он еще не создан будет создан автоматически +conn = sqlite3.connect('sqlite.db') +print('База данных открыта') + +# Создаем таблицу +conn.execute('CREATE TABLE COMPANY' + ' (ID INT PRIMARY KEY NOT NULL,' + ' NAME TEXT NOT NULL,' + ' AGE INT NOT NULL,' + ' ADDRESS CHAR(50),' + ' SALARY REAL);') +print('Таблица создана') + +# Добавляем данные +conn.execute("INSERT INTO COMPANY (ID, NAME, AGE, ADDRESS, SALARY) " + "VALUES (1, 'Paul', 32, 'California', 20000.00)") +conn.execute("INSERT INTO COMPANY (ID, NAME, AGE, ADDRESS, SALARY) " + "VALUES (2, 'Allen', 25, 'Texas', 15000.00)") +conn.execute("INSERT INTO COMPANY (ID, NAME, AGE, ADDRESS, SALARY) " + "VALUES (3, 'Teddy', 23, 'Norway', 20000.00)") +conn.execute("INSERT INTO COMPANY (ID, NAME, AGE, ADDRESS, SALARY) " + "VALUES (4, 'Mark', 25, 'Richmond', 65000.00)") +conn.commit() +print('Данные добавлены') + +# Читаем данные +cursor = conn.cursor() +print("############Test row_factory 1############") +cursor.row_factory = sqlite3.Row +cursor.execute('SELECT id, name, address, salary from COMPANY WHERE id = 1') +for row in cursor: + print(dict(row)) +print("##############End of test 1###############") + +print("############Test row_factory 2############") +cursor.row_factory = None +cursor.execute('SELECT id, name, address, salary from COMPANY WHERE id = 1') +for row in cursor: + print(row) +print("##############End of test 2###############") + +# Изменяем данные +conn.execute('UPDATE COMPANY set salary = 25000.00 WHERE id = 1') +conn.commit() +print('Данные изменены') +# Проверяем, что получилось +cursor = conn.execute('SELECT id, name, address, salary from ' + 'COMPANY WHERE id = 1') +print(cursor.fetchone()) + +# Удаляем данные +conn.execute('DELETE from COMPANY where id=2;') +conn.commit() +print('Данные удалены') +# Проверяем, что получилось +cursor = conn.execute('SELECT id, name, address, salary from COMPANY') +for row in cursor: + print(row) + +# Изменяем данные +conn.execute('UPDATE COMPANY set salary = 25000.00 WHERE id = 1') +conn.commit() +print('Данные снова изменены') + +# Проверяем, что получилось +cursor = conn.execute('SELECT id, name, address, salary from ' + 'COMPANY WHERE id = 1') +print(cursor.fetchone()) + +# При необходимости подставить в запрос значения, полученные в коде Python +# НЕ следует использовать строковые операции (например, конкатенацию) +# с текстом запроса! +# Для подстановки параметров в запрос необходимо указать специальный символ +# '?' на местах подстановки в тексте запроса, а параметры передать в кортеже +# в соответствующем порядке в тот же метод execute(). +conn.execute("INSERT INTO COMPANY (ID, NAME, AGE, ADDRESS, SALARY)" + "VALUES (?, ?, ?, ?, ?)", + (5, 'Allen', 32, 'Texas', 15000.00)) +conn.commit() +print('Новые данные добавлены') + +# Проверяем, что получилось +cursor = conn.execute('SELECT id, name, address, salary from COMPANY') +for row in cursor: + print(row) + +conn.execute('DROP TABLE COMPANY') +print('Таблица удалена') + +conn.close() diff --git a/Useful/for_lec19/cx_oracle_example.py b/Useful/for_lec19/cx_oracle_example.py new file mode 100644 index 0000000..ac23d28 --- /dev/null +++ b/Useful/for_lec19/cx_oracle_example.py @@ -0,0 +1,10 @@ +import cx_Oracle + + +host = '192.168.10.21' +username = 'USER' +password = '123456' +port = 1521 +sid = 'mydb' +dbname = cx_Oracle.makedsn(host, port, sid=sid) +connection = cx_Oracle.connect(username, password, dbname) diff --git a/Useful/for_lec19/db_client.py b/Useful/for_lec19/db_client.py new file mode 100644 index 0000000..1b69106 --- /dev/null +++ b/Useful/for_lec19/db_client.py @@ -0,0 +1,91 @@ +import logging +import csv +import cx_Oracle +import sqlite3 + + +DB_CODE = 'cp1251' + + +def OutputTypeHandler(cursor, name, defaultType, size, precision, scale): + if defaultType == cx_Oracle.CLOB: + return cursor.var(cx_Oracle.LONG_STRING, arraysize=cursor.arraysize) + if defaultType == cx_Oracle.BLOB: + return cursor.var(cx_Oracle.LONG_BINARY, arraysize=cursor.arraysize) + + +class DBClient(object): + + def __init__(self, dbtype='sqlite', dbname='tmp.db', + username=None, password=None): + self.dbtype = dbtype + self.conn = self.connect(dbtype, dbname, username, password) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.conn.close() + + + @staticmethod + def connect(dbtype, dbname, username=None, password=None): + connection = None + try: + logging.debug('Create connection to db: dbtype={}, dbname={}'.format(dbtype, dbname)) + if dbtype == 'sqlite': + connection = sqlite3.connect(dbname) + connection.row_factory = sqlite3.Row + elif dbtype == 'oracle': + connection = cx_Oracle.connect(username, password, dbname) + connection.outputtypehandler = OutputTypeHandler + except Exception as err: + logging.critical('Error: cannot connect to db. {}'.format(err)) + raise err + return connection + + @staticmethod + def show_multi_data(headline, rows, csvfilename=None): + if csvfilename: + with open(csvfilename, 'wb') as csvfile: + writer = csv.DictWriter(csvfile, fieldnames=headline) + writer.writeheader() + for r in rows: + # d = {k: v if isinstance(v, bytes) else v for k, v in dict(r).items()} + # writer.writerow(d) + writer.writerow(dict(r)) + else: + logging.info(headline) + for r in rows: + logging.info(' {},'.format([x.decode(DB_CODE) if isinstance(x, bytes) else x for x in r])) + + def get_student_info(self): + cur = self.conn.cursor() + cur.execute('SELECT s.*, o.DESCRIPTION, o.INSERTED, os.STATUS_NAME ' + 'FROM edu_student s, edu_object o, edu_object_status os ' + 'WHERE s.OBJECT_ID = o.OBJECT_ID AND o.OBJECT_STATUS_ID = os.OBJECT_STATUS_ID') + col_names = [each[0] for each in cur.description] + cur.rowfactory = lambda *args: dict(zip([d[0] for d in cur.description], args)) + return col_names, cur.fetchall() + + def get_contract_info(self): + cur = self.conn.cursor() + cur.execute('SELECT co.CONTRACT_NUMBER, co.COST, co.BEGIN_DATE, co.END_DATE, ' + 'co.CREATION_DATE, co.CUSTOMER, ' + 'o2.OBJECT_NAME, o.DESCRIPTION, o.INSERTED, os.STATUS_NAME, ' + 's.LAST_NAME, s.FIRST_NAME, s.SECOND_NAME ' + 'FROM edu_contract co, edu_object o, edu_object o2, edu_student s, edu_object_status os ' + 'WHERE o.OBJECT_ID = co.OBJECT_ID AND o2.OBJECT_ID = co.COURSE_ID AND os.OBJECT_STATUS_ID = o.OBJECT_STATUS_ID ' + 'AND s.OBJECT_ID = co.STUDENT_ID') + col_names = [each[0] for each in cur.description] + cur.rowfactory = lambda *args: dict(zip([d[0] for d in cur.description], args)) + return col_names, cur.fetchall() + + def export_data_to_csv(self): + col_names, rows = self.get_student_info() + self.show_multi_data(col_names, rows, 'students.csv') + col_names, rows = self.get_contract_info() + self.show_multi_data(col_names, rows, 'contract.csv') + # self.show_multi_data(col_names, rows) + + diff --git a/Useful/for_lec19/db_details.py b/Useful/for_lec19/db_details.py new file mode 100644 index 0000000..f0ddbc8 --- /dev/null +++ b/Useful/for_lec19/db_details.py @@ -0,0 +1,59 @@ +import sqlite3 +import os + + +class DBClient: + def __init__(self, dbname): + self._conn = sqlite3.connect(dbname) + self._conn.row_factory = sqlite3.Row + print("Соединение открылось") + + def configure_db(self): + cur = self._conn.cursor() + + # Создаем таблицу Details + cur.execute("CREATE TABLE Details" + " (Id INTEGER PRIMARY KEY AUTOINCREMENT," + " Name CHAR(128) NOT NULL," + " Price INTEGER NOT NULL)") + self._conn.commit() + + + def insert_detail(self, id, name, price): + cur = self._conn.cursor() + cur.execute("INSERT INTO Details (Id, Name, Price)" + " VALUES (:id, :name, :price)", + {'id': id, 'name': name, 'price': price}) + self._conn.commit() + + + def select_detail(self, detail_id): + cur = self._conn.cursor() + cur.execute("SELECT Id, Name, Price FROM Details WHERE Id = :detail_id", + {'detail_id': detail_id}) + return cur.fetchone() + + def __del__(self): + self._conn.close() + print("Соединение закрылось") + + +if __name__ == "__main__": + db_name = "details.db" + db_exists = os.path.exists(db_name) + + db_client = DBClient(db_name) + + if not db_exists: + db_client.configure_db() + + db_client.insert_detail(1, "Гайка", 50) + db_client.insert_detail(2, "Винт", 60) + + while i := input("Введите номер детали: "): + num = int(i) + res = db_client.select_detail(num) + if res: + print(dict(res)) + else: + print(f"Нет детали с номером {i}") diff --git a/Useful/for_lec19/details_client.py b/Useful/for_lec19/details_client.py new file mode 100644 index 0000000..63f822c --- /dev/null +++ b/Useful/for_lec19/details_client.py @@ -0,0 +1,30 @@ +import socket +import pickle +import random +import time + + +class TcpClient: + def __init__(self, host, port): + self.host = host + self.port = port + self._socket = None + + def run(self): + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.connect((self.host, self.port)) + while i := input("Введите номер детали (или stop): "): + if i == "stop": + self._socket.send(pickle.dumps(i)) + break + else: + num = int(i) + self._socket.send(pickle.dumps(num)) + data = self._socket.recv(1024) + print(f'Received: {pickle.loads(data)}') + self._socket.close() + + +if __name__ == '__main__': + myclient = TcpClient(host='127.0.0.1', port=5555) + myclient.run() \ No newline at end of file diff --git a/Useful/for_lec19/details_server.py b/Useful/for_lec19/details_server.py new file mode 100644 index 0000000..1a749d7 --- /dev/null +++ b/Useful/for_lec19/details_server.py @@ -0,0 +1,65 @@ +import threading +import socket +import pickle +import db_details + + +DB_NAME = "details.db" + + +class ClientThread(threading.Thread): + def __init__(self, conn, addr): + super().__init__() + self._connection = conn + self._address = addr + + def run(self): + stop = False + db_client = db_details.DBClient(DB_NAME) + while not stop: + request = self._connection.recv(1024) + num = pickle.loads(request) + if num == "stop": + stop = True + else: + res = db_client.select_detail(num) + if res: + data = dict(res) + else: + data = f"Нет детали с номером {num}" + self._connection.send(pickle.dumps(data)) + self._connection.close() + + +class TcpServer: + def __init__(self, host, port): + self.host = host + self.port = port + self._socket = None + self._running = False + + def run(self): + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._socket.bind((self.host, self.port)) + self._socket.listen(5) + self._running = True + + print('Server is up') + while self._running: + conn, addr = self._socket.accept() + ClientThread(conn, addr).start() + + def stop(self): + self._running = False + self._socket.close() + print('Server is down') + + +if __name__ == '__main__': + srv = TcpServer(host='127.0.0.1', port=5555) + try: + srv.run() + except KeyboardInterrupt: + srv.stop() + diff --git a/Useful/for_lec19/example_db_api.py b/Useful/for_lec19/example_db_api.py new file mode 100644 index 0000000..9f37a90 --- /dev/null +++ b/Useful/for_lec19/example_db_api.py @@ -0,0 +1,242 @@ +# Импортируем библиотеку, соответствующую типу нашей базы данных +import sqlite3 +# Импортируем os для проверки существования файла базы данных +import os + + +def configure_db(conn): + cur = conn.cursor() + + # Создаем таблицу Employees + cur.execute("CREATE TABLE Employees" + " (Id INTEGER PRIMARY KEY AUTOINCREMENT," + " Name CHAR(128) NOT NULL," + " Position CHAR(64) NOT NULL," + " Bonus INTEGER DEFAULT 0," + " Login CHAR(16) NOT NULL," + " Password CHAR(16) NOT NULL)") + + # Создаем таблицу Projects + cur.execute("CREATE TABLE Projects" + " (Id INTEGER PRIMARY KEY AUTOINCREMENT," + " Name CHAR(128) NOT NULL)") + + # Создаем таблицу PositionSalary + cur.execute("CREATE TABLE PositionSalary" + " (Position CHAR(64) PRIMARY KEY NOT NULL," + " Salary INTEGER NOT NULL)") + + # Создаем таблицу EmployeeProject + cur.execute("CREATE TABLE EmployeeProject" + " (EmployeeId INTEGER," + " ProjectId INTEGER," + " PRIMARY KEY (EmployeeId, ProjectId))") + + +# Добавление записей в таблицу Проект +def insert_project(conn, name): + # Создаем курсор - специальный объект, + # который делает запросы и получает их результаты + cur = conn.cursor() + # Делаем INSERT запрос к базе данных, используя обычный SQL-синтаксис + cur.execute("INSERT INTO Projects (Name)" + " VALUES (:name)", + {'name': name}) + # Если мы не просто читаем, но и вносим изменения в базу данных + # - необходимо сохранить транзакцию + conn.commit() + + +# Добавление записей в таблицу ДолжностьОклад +def insert_position(conn, position, salary): + cur = conn.cursor() + cur.execute("INSERT INTO PositionSalary (Position, Salary)" + " VALUES (:position, :salary)", + {'position': position, 'salary': salary}) + conn.commit() + +# Добавление записей в таблицу Сотрудник +def insert_employee(conn, name, position, bonus, login, pwd): + cur = conn.cursor() + cur.execute("INSERT INTO Employees (Name, Position, Bonus, Login, Password)" + " VALUES (:name, :position, :bonus, :login, :pwd)", + {'name': name, 'position': position, 'bonus': bonus, + 'login': login, 'pwd': pwd}) + conn.commit() + +# Добавление записей в таблицу СотрудникПроект +def add_employee_to_project(conn, employee_id, project_id): + cur = conn.cursor() + cur.execute("INSERT INTO EmployeeProject (EmployeeId, ProjectId)" + " VALUES (:employeeId, :projectId)", + {'employeeId': employee_id, 'projectId': project_id}) + conn.commit() + +# Проверка наличия пользователя в базе данных +# с указанным логином/пролем +def authentication(conn, login, pwd): + cur = conn.cursor() + # Делаем SELECT запрос к базе данных, используя обычный SQL-синтаксис + cur.execute("SELECT E.Id, E.Name, E.Position, EP.ProjectId" + " FROM Employees AS E, EmployeeProject AS EP" + " WHERE E.Id = EP.EmployeeId" + " AND E.Login = :login AND E.Password = :pwd", + {'login': login, 'pwd': pwd}) + # Получаем результат сделанного запроса + return cur.fetchone() + +def authentication2(conn, login, pwd): + cur = conn.cursor() + cur.execute("SELECT E.Id, E.Name, E.Position, EP.ProjectId" + " FROM Employees AS E, EmployeeProject AS EP" + " WHERE E.Id = EP.EmployeeId" + " AND E.Login = ? AND E.Password = ?", + (login, pwd)) + return cur.fetchone() + + +def bad_authentication(conn, login, pwd): + cur = conn.cursor() + # Неправильно: + cur.execute("SELECT E.Id, E.Name, E.Position, EP.ProjectId" + " FROM Employees AS E, EmployeeProject AS EP" + " WHERE E.Id = EP.EmployeeId" + " AND E.Login = {login} AND E.Password = {pwd}". + format(login=login, pwd=pwd)) + # Тоже неправильно: + # cur.execute(f"SELECT E.Id, E.Name, E.Position, EP.ProjectId" + # f" FROM Employees AS E, EmployeeProject AS EP" + # f" WHERE E.Id = EP.EmployeeId" + # f" AND E.Login = {login} AND E.Password = {pwd}". + # format(login=login, pwd=pwd)) + return cur.fetchone() + + +# Вывод информации для менеджера проекта +# Соединяем таблицы Employees, PositionSalary, EmployeeProject +def show_manager_info(conn, project_id): + cur = conn.cursor() + cur.execute("SELECT E.Id, E.Name, P.Salary + E.Bonus As Pay" + " FROM Employees AS E, PositionSalary AS P, " + " EmployeeProject AS EP" + " WHERE E.Position = P.Position" + " AND E.Id = EP.EmployeeId" + " AND EP.ProjectId = :project_id", + {'project_id': project_id}) + print("Информация для менеджера:") + for row in cur.fetchall(): + print(dict(row)) + +# Вывод информации для сотрудника +# Соединяем таблицы Employees, PositionSalary +def show_employee_info(conn, employee_id): + cur = conn.cursor() + cur.execute("SELECT E.Id, E.Name, P.Salary + E.Bonus As Pay" + " FROM Employees AS E, PositionSalary AS P" + " WHERE E.Position = P.Position" + " AND E.Id = :employee_id", + {'employee_id': employee_id}) + print("Информация для сотрудника:") + for row in cur.fetchall(): + print(dict(row)) + +# Проверка наличия указанного сотрудника в указанном проекте +def is_employee_in_project(conn, employee_id, project_id): + cur = conn.cursor() + cur.execute("SELECT EP.ProjectId" + " FROM EmployeeProject AS EP" + " WHERE EP.EmployeeId = :employee_id" + " AND EP.ProjectId = :project_id", + {'employee_id': employee_id, 'project_id': project_id}) + return bool(cur.fetchone()) + +# Изменение премии сотрудника +def update_employee_bonus(conn, employee_id, new_bonus): + cur = conn.cursor() + # Делаем UPDATE запрос к базе данных, используя обычный SQL-синтаксис + cur.execute("UPDATE Employees" + " SET Bonus = :new_bonus" + " WHERE Id = :employee_id", + {'employee_id': employee_id, 'new_bonus': new_bonus}) + conn.commit() + + +# Удаление сотрудника из проекта (но не из базы данных) +def delete_employee_from_project(conn, employee_id, project_id): + cur = conn.cursor() + # Делаем DELETE запрос к базе данных, используя обычный SQL-синтаксис + cur.execute("DELETE FROM EmployeeProject" + " WHERE EmployeeId = :employee_id" + " AND ProjectId = :project_id", + {'employee_id': employee_id, 'project_id': project_id}) + conn.commit() + + +def drop_db(conn): + cur = conn.cursor() + cur.execute("DROP TABLE Employees") + cur.execute("DROP TABLE Projects") + cur.execute("DROP TABLE PositionSalary") + cur.execute("DROP TABLE EmployeeProject") + + +if __name__ == "__main__": + db_name = "example.db" + db_exists = os.path.exists(db_name) + + # Подключаемся к базе данных + # Если файл базы данных еще не создан, он создастся автоматически. + # Если указать :memory: вместо имени файла - база будет создана + # в оперативной памяти без сохранения в файле. + conn = sqlite3.connect(db_name) + conn.row_factory = sqlite3.Row + if not db_exists: + configure_db(conn) + + insert_project(conn, "Важный") + insert_project(conn, "Срочный") + insert_position(conn, "инженер", 50000) + insert_position(conn, "старший инженер", 51000) + insert_position(conn, "менеджер проекта", 100000) + insert_employee(conn, "Иванов И.И.", "инженер", 30000, + "ivanovi", "ivanov123") + insert_employee(conn, "Петров П.П.", "старший инженер", 50000, + "petrovp", "p1e2t3") + insert_employee(conn, "Сидоров С.С.", "менеджер проекта", 30000, + "sidorovs", "zayka88") + add_employee_to_project(conn, 1, 1) + add_employee_to_project(conn, 2, 1) + add_employee_to_project(conn, 2, 2) + add_employee_to_project(conn, 3, 2) + + login = input("Логин: ") + pwd = input("Пароль: ") + res = authentication(conn, login, pwd) + if res: + user = dict(res) + print("Здравствуйте, {}".format(user['Name'])) + if user['Position'] == "менеджер проекта": + show_manager_info(conn, user['ProjectId']) + + id_upd = int(input("Изменение премии. ID сотрудника (0 - отмена): ")) + if id_upd: + if (id_upd != user['Id'] and + is_employee_in_project(conn, id_upd, user['ProjectId'])): + new_bonus = input("Новая премия: ") + update_employee_bonus(conn, id_upd, new_bonus) + else: + print("Невозможно изменить премию для данного сотрудника") + + id_del = int(input("Удаление сотрудника. ID сотрудника (0 - отмена): ")) + if id_del: + if id_del != user['Id']: + delete_employee_from_project(conn, id_del, user['ProjectId']) + else: + print("Невозможно удалить данного сотрудника из проекта") + else: + show_employee_info(conn, user['Id']) + else: + print("Доступ запрещен") + + # Не забываем закрыть соединение с базой данных после работы + conn.close() diff --git a/Useful/for_lec19/example_sqlalchemy.py b/Useful/for_lec19/example_sqlalchemy.py new file mode 100644 index 0000000..d6466df --- /dev/null +++ b/Useful/for_lec19/example_sqlalchemy.py @@ -0,0 +1,274 @@ +import os +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import sessionmaker +from sqlalchemy import and_ +from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound +from sqlalchemy.orm.session import close_all_sessions + +Base = declarative_base() + +# Создаем класс, отображающий таблицу +class Employee(Base): + __tablename__ = 'employee' + id = Column(Integer, primary_key=True) + name = Column(String, nullable=False) + position = Column(String, ForeignKey('position_salary.position'), + nullable=False) + bonus = Column(Integer, default=0) + login = Column(String, nullable=False, unique=True) + password = Column(String, nullable=False) + def __repr__(self): + return "".\ + format(id=self.id, name=self.name, + pos=self.position, bon=self.bonus, + log=self.login, pwd=self.password) + +class Project(Base): + __tablename__ = 'project' + id = Column(Integer, primary_key=True) + name = Column(String, nullable=False) + def __repr__(self): + return "".format(id=self.id, + name=self.name) + +class PositionSalary(Base): + __tablename__ = 'position_salary' + position = Column(String, primary_key=True) + salary = Column(Integer, nullable=False) + def __repr__(self): + return "".format( + pos=self.position, sal=self.salary) + +class EmployeeProject(Base): + __tablename__ = 'employee_project' + employee_id = Column(Integer, ForeignKey('employee.id'), primary_key=True) + project_id = Column(Integer, ForeignKey('project.id'), primary_key=True) + def __repr__(self): + return "".\ + format(e_id=self.employee_id, p_id=self.project_id) + + +class DBClient: + + def __init__(self, dbtype='sqlite', dbname='/example.db', + username=None, password=None): + self._engine = self._get_engine(dbtype, dbname, username, password) + + def __enter__(self): + self._session = sessionmaker(bind=self._engine)() + return self + + def __exit__(self, exc_type, exc_value, traceback): + close_all_sessions() + + @staticmethod + def _get_engine(dbtype, dbname, username=None, password=None): + if username: + if password: + login = '{u}:{p}'.format(u=username, p=password) + else: + login = username + dbstr = '{l}@{db}'.format(l=login, db=dbname) + else: + dbstr = dbname + + # Создаем базу данных + # Либо без файла (в оперативной памяти) + # Либо с файлом, указывая относительный путь к нему: engine = create_engine('sqlite:///mybase.db') + # Либо абсолютный путь: engine = create_engine(r'sqlite:///C:\Users\User\Desktop\mybase.db') + engine = create_engine('{}:///{}'.format(dbtype, dbstr)) + return engine + + def create_schema(self): + # Создаем схему + Base.metadata.create_all(self._engine) + + def delete_schema(self): + # Удаляем схему + Base.metadata.drop_all(self._engine) + + def insert_position(self, position, salary): + self._session.add(PositionSalary(position=position, salary=salary)) + self._session.commit() + + def insert_project(self, name): + p = Project(name=name) + self._session.add(p) + self._session.commit() + return p.id + + def insert_employee(self, name, position, bonus, login, password): + e = Employee(name=name, position=position, bonus=bonus, + login=login, password=password) + self._session.add(e) + self._session.commit() + return e.id + + def add_employee_to_project(self, employee_id, project_id): + self._session.add(EmployeeProject(employee_id=employee_id, + project_id=project_id)) + self._session.commit() + + + def add_new_employee_to_project(self, name, position, bonus, login, password, project_id): + e = Employee(name=name, position=position, bonus=bonus, + login=login, password=password) + self._session.add(e) + self._session.commit() + self._session.add(EmployeeProject(employee_id=e.id, + project_id=project_id)) + self._session.commit() + + + # Проверка наличия пользователя в базе данных + # с указанным логином/паролем + def authentication(self, login, password): + try: + res = self._session.query(Employee.id, Employee.name, + Employee.position, EmployeeProject.project_id).\ + join(EmployeeProject, EmployeeProject.employee_id == Employee.id). \ + filter(and_(Employee.login == login, + Employee.password == password)).\ + one() + return res + except MultipleResultsFound: + print("Multiple Results Found") + except NoResultFound: + print("No Result Found") + return None + + # Проверка наличия указанного сотрудника в указанном проекте + def is_employee_in_project(self, employee_id, project_id): + try: + res = self._session.query(EmployeeProject.project_id).\ + filter(and_(EmployeeProject.employee_id == employee_id, + EmployeeProject.project_id == project_id)).\ + one() + return True + except MultipleResultsFound: + print("Multiple Results Found") + except NoResultFound: + print("No Result Found") + return None + + + # Вывод информации для сотрудника + # Соединяем таблицы Employees, PositionSalary + def show_employee_info(self, employee_id): + res = self._session.query(Employee.id, Employee.name, + (PositionSalary.salary + + Employee.bonus).label("Pay")).\ + filter(and_(Employee.position == PositionSalary.position, + Employee.id == employee_id)).\ + all() + print("Информация для сотрудника:") + for row in res: + print(row) + return res + + # Вывод информации для менеджера проекта + # Соединяем таблицы Employees, PositionSalary, EmployeeProject + def show_manager_info(self, project_id): + res = self._session.query(Employee.id, Employee.name, + (PositionSalary.salary + + Employee.bonus).label("Pay")). \ + filter(and_(Employee.position == PositionSalary.position, + Employee.id == EmployeeProject.employee_id, + EmployeeProject.project_id == project_id)). \ + all() + print("Информация для менеджера:") + for row in res: + print(row) + return res + + # Изменение премии сотрудника + def update_employee_bonus(self, employee_id, new_bonus): + e = self._session.query(Employee).get(employee_id) + if e: + e.bonus = new_bonus + self._session.add(e) + self._session.commit() + + # Удаление сотрудника из проекта (но не из базы данных) + def delete_employee_from_project(self, employee_id, project_id): + ep = self._session.query(EmployeeProject).get((employee_id, project_id)) + if ep: + self._session.delete(ep) + self._session.commit() + + + def show_all(self): + print(self._session.query(PositionSalary).all()) + print(self._session.query(Project).all()) + print(self._session.query(Employee).all()) + print(self._session.query(EmployeeProject).all()) + + +if __name__ == "__main__": + db_type = "sqlite" + db_name = "example.db" + db_exists = os.path.exists(db_name) + + if not db_exists: + with DBClient(db_type, db_name) as dbc: + dbc.create_schema() + + dbc.insert_position("инженер", 50000) + dbc.insert_position("старший инженер", 51000) + dbc.insert_position("менеджер проекта", 100000) + + pid = dbc.insert_project("Важный") + eid = dbc.insert_employee("Иванов И.И.", "инженер", 30000, + "ivanovi", "ivanov123") + dbc.add_employee_to_project(eid, pid) + + eid = dbc.insert_employee("Петров П.П.", "старший инженер", 50000, + "petrovp", "p1e2t3") + dbc.add_employee_to_project(eid, pid) + + pid = dbc.insert_project("Срочный") + dbc.add_employee_to_project(eid, pid) + + eid = dbc.insert_employee("Сидоров С.С.", "менеджер проекта", 30000, + "sidorovs", "zayka88") + dbc.add_employee_to_project(eid, pid) + + + login = input("Логин: ") + pwd = input("Пароль: ") + with DBClient(db_type, db_name) as dbc: + #dbc.show_all() + res = dbc.authentication(login, pwd) + if res: + user = res._asdict() + print("Здравствуйте, {}".format(user['name'])) + if user['position'] == "менеджер проекта": + dbc.show_manager_info(user['project_id']) + + id_upd = int(input("Изменение премии. ID сотрудника (0 - отмена): ")) + if id_upd: + if (id_upd != user['id'] and + dbc.is_employee_in_project(id_upd, user['project_id'])): + new_bonus = input("Новая премия: ") + dbc.update_employee_bonus(id_upd, new_bonus) + print("Результат:") + dbc.show_manager_info(user['project_id']) + else: + print("Невозможно изменить премию для данного сотрудника") + + id_del = int(input("Удаление сотрудника. ID сотрудника (0 - отмена): ")) + if id_del: + if id_del != user['id']: + dbc.delete_employee_from_project(id_del, user['project_id']) + print("Результат:") + dbc.show_manager_info(user['project_id']) + else: + print("Невозможно удалить данного сотрудника из проекта") + else: + dbc.show_employee_info(user['id']) + else: + print("Доступ запрещен") diff --git a/Useful/for_lec19/finance_db.py b/Useful/for_lec19/finance_db.py new file mode 100644 index 0000000..8492d51 --- /dev/null +++ b/Useful/for_lec19/finance_db.py @@ -0,0 +1,61 @@ +import sqlite3 + + +# Подключаемся к базе данных +# Файл базы данных (если он еще не создан будет создан автоматически +conn = sqlite3.connect(':memory:') +cur = conn.cursor() +print('База данных открыта') + +# Создаем таблицу +cur.execute('CREATE TABLE USERS' + ' (ID INTEGER PRIMARY KEY AUTOINCREMENT,' + ' LOGIN CHAR(50) NOT NULL,' + ' PASSWORD CHAR(50) NOT NULL,' + ' SALARY REAL);') +print('Таблица создана') + +# Добавляем данные +cur.execute("INSERT INTO USERS (LOGIN, PASSWORD, SALARY)" + "VALUES ('Ivan', 'coolpwd', 100000)") +cur.execute("INSERT INTO USERS (LOGIN, PASSWORD, SALARY)" + "VALUES ('Petr', 'iampetr', 50000)") +cur.execute("INSERT INTO USERS (LOGIN, PASSWORD, SALARY)" + "VALUES ('Simon', '123', 30000)") +conn.commit() +print('Данные добавлены') + +# Читаем данные +cur.execute('SELECT id, login, password from USERS') +for row in cur.fetchall(): + print(row) + +login = input('Input login: ') +password = input('Input password: ') + +# req = "SELECT login, salary from USERS WHERE login='{}' AND password='{}'".format(login, password) +# print('This is request: {}'.format(req)) +# cur.execute(req) +# print('Output data:') +# rows = cur.fetchall() +# if not len(rows): +# print('incorrect login/password') +# else: +# for row in rows: +# print(row) + +cursor = conn.execute("SELECT login, salary from USERS WHERE login=? AND password=?", + (login, password)) +print('Output data 2:') +for row in cursor: + print(row) + +conn.execute('DROP TABLE USERS') +print('Таблица удалена') + +conn.close() + + + + + diff --git a/Useful/for_lec19/test_db_client.py b/Useful/for_lec19/test_db_client.py new file mode 100644 index 0000000..296661f --- /dev/null +++ b/Useful/for_lec19/test_db_client.py @@ -0,0 +1,30 @@ +from unittest import mock +import db_details + + +class TestDBClient: + # рабочий вариант теста с патчингом БД для тестирования изолированного конструктора + def test_dbclient_init(self): + with mock.patch('db_details.sqlite3') as sqlite_mock: + connection_mock = mock.Mock() + sqlite_mock.connect.return_value = connection_mock + sqlite_mock.Row = "fake_row" + dbname = "fake_db" + db_client = db_details.DBClient(dbname) + sqlite_mock.connect.assert_called_once_with(dbname) + assert db_client._conn.row_factory == sqlite_mock.Row + + # рабочий вариант теста DBClient в интеграции с БД + def test_data_add(self): + db_client = db_details.DBClient(":memory:") + db_client.configure_db() + id, name, price = 1, "Гайка", 50 + db_client.insert_detail(id, name, price) + res = db_client.select_detail(id) + assert res + res_as_dict = dict(res) + assert res_as_dict['Id'] == id + assert res_as_dict['Name'] == name + assert res_as_dict['Price'] == price + + diff --git a/Useful/for_lec20/check_redis.py b/Useful/for_lec20/check_redis.py new file mode 100644 index 0000000..4b24d48 --- /dev/null +++ b/Useful/for_lec20/check_redis.py @@ -0,0 +1,67 @@ +import time +import redis + +# Создаем подключение +r = redis.Redis(host='localhost', port=6379, db=0) + +# Добавляем элемент - пару ключ-значение +r.set('name', 'John') +# Получаем значение по ключу +print("r.get('name'): ", r.get('name')) +# Определяем тип значения по ключу +print("r.type('name'): ", r.type('name')) +# Удаляем элемент по ключу +r.delete('name') +print("r.get('name'): ", r.get('name')) + +# set всегда добавляет значение строкового типа +r.set('my_int', 2) +print("r.get('my_int'): ", r.get('my_int')) +print("r.type('my_int'): ", r.type('my_int')) +# Инкрементируем значение по ключу, которое для данной +# операции интерпретируется как 64-битное знаковое целое +print("r.incr('my_int'): ", r.incr('my_int')) +# Проверяем существование значения по ключу +print("r.exists('my_int'): ", r.exists('my_int')) +r.set('temp_value', 'value') +# Задаем время жизни ключа (в секундах), по истечении +# которого он будет автоматически удален с сервера +r.expire('temp_value', 5) +# Узнаем оставшееся время жизни ключа +print("r.ttl('temp_value'): ", r.ttl('temp_value')) +print("r.get('temp_value'): ", r.get('temp_value')) + +time.sleep(6) +print("After 6 seconds...") + +print("r.ttl('temp_value'): ", r.ttl('temp_value')) +print("r.get('temp_value'): ", r.get('temp_value')) +print("r.exists('temp_value'): ", r.exists('temp_value')) + +# hashset - хэшсет +# Добавляем пару ключ-значение в хэшсет user:1 +r.hset('user:1', 'name', 'John') +# Добавляем еще одну пару ключ-значение в хэшсет user:1 +r.hset('user:1', 'email', 'john@gmail.com') +print("r.hget('user:1', 'name'): ", r.hget('user:1', 'name')) +print("r.hkeys('user:1'): ", r.hkeys('user:1')) +print("r.hgetall('user:1'): ", r.hgetall('user:1')) +# list - список # Добавляем элементы в список +r.rpush('my_list', 'elem1') +r.rpush('my_list', 'elem2') +r.rpush('my_list', 'elem3') +r.rpush('my_list', 'elem4') +print("r.llen('my_list'): ", r.llen('my_list')) +print("r.lindex('my_list', 0): ", r.lindex('my_list', 0)) +print("r.lrange('my_list', 1, 3): ", r.lrange('my_list', 1, 3)) + +# Реализация паттерна издатель-подписчик +p = r.pubsub(ignore_subscribe_messages=True) +p.subscribe('my-chat') +print("p.get_message(): ", p.get_message()) +r.publish('my-chat', 'user: Hello!') +while True: + msg = p.get_message() + if msg: + print("p.get_message(): ", msg) + break diff --git a/Useful/for_lec20/cqlsh_examples.txt b/Useful/for_lec20/cqlsh_examples.txt new file mode 100644 index 0000000..d2604f0 --- /dev/null +++ b/Useful/for_lec20/cqlsh_examples.txt @@ -0,0 +1,61 @@ +cqlsh> use example; +cqlsh:example> INSERT INTO users (username, fullname, regdate, status) VALUES ("ivanovi", "Иван Иванов", 01.01.2020, "Available"); +SyntaxException: line 1:73 no viable alternative at input ',' +cqlsh:example> INSERT INTO users (username, fullname, regdate, status) VALUES ("ivanovi", "Иван Иванов", "2020-01-01", "Available"); +SyntaxException: line 1:73 no viable alternative at input ',' +cqlsh:example> INSERT INTO users (username, fullname, regdate, status) VALUES ('ivanovi', 'Иван Иванов', '2020-01-01', 'Available'); +InvalidRequest: Error from server: code=2200 [Invalid query] message="Missing mandatory PRIMARY KEY part id" +cqlsh:example> INSERT INTO users (id, username, fullname, regdate, status) VALUES (1, 'ivanovi', 'Иван Иванов', '2020-01-01', 'Available'); +cqlsh:example> INSERT INTO users (id, username, fullname, regdate, status) VALUES (2, 'petrovp', 'Петр Петров', '2020-02-02', 'Busy'); +cqlsh:example> SELECT username FROM users WHERE id = 1; + + username +---------- + ivanovi + +(1 rows) +cqlsh:example> SELECT * FROM users WHERE id = 1; + + id | fullname | regdate | status | username +----+-------------+------------+-----------+---------- + 1 | Иван Иванов | 2020-01-01 | Available | ivanovi + +(1 rows) +cqlsh:example> UPDATE users SET status = 'Busy' WHERE id = 1; +cqlsh:example> SELECT * FROM users WHERE id = 1; + + id | fullname | regdate | status | username +----+-------------+------------+--------+---------- + 1 | Иван Иванов | 2020-01-01 | Busy | ivanovi + +(1 rows) +cqlsh:example> INSERT INTO users (id, username, fullname, regdate, status) VALUES (3, "orlovi", 'Илья Орлов', '2020-03-03', 'Available'); +SyntaxException: line 1:79 no viable alternative at input ',' +cqlsh:example> INSERT INTO users (id, username, fullname, regdate, status) VALUES (3, 'orlovi', 'Илья Орлов', '2020-03-03', 'Available'); +cqlsh:example> SELECT * FROM users WHERE id = 3; + + id | fullname | regdate | status | username +----+------------+------------+-----------+---------- + 3 | Илья Орлов | 2020-03-03 | Available | orlovi + +(1 rows) +cqlsh:example> SELECT * FROM users; + + id | fullname | regdate | status | username +----+-------------+------------+-----------+---------- + 1 | Иван Иванов | 2020-01-01 | Busy | ivanovi + 2 | Петр Петров | 2020-02-02 | Busy | petrovp + 3 | Илья Орлов | 2020-03-03 | Available | orlovi + +(3 rows) +cqlsh:example> DELETE FROM users WHERE id = 3; +cqlsh:example> SELECT * FROM users; + + id | fullname | regdate | status | username +----+-------------+------------+--------+---------- + 1 | Иван Иванов | 2020-01-01 | Busy | ivanovi + 2 | Петр Петров | 2020-02-02 | Busy | petrovp + +(2 rows) +cqlsh:example> + diff --git a/Useful/for_lec20/mongodb_test.py b/Useful/for_lec20/mongodb_test.py new file mode 100644 index 0000000..ec59fb1 --- /dev/null +++ b/Useful/for_lec20/mongodb_test.py @@ -0,0 +1,44 @@ +# Подключаемся к базе MongoDB на локальной машине +import mongoengine as me + + +# Объявляем коллекцию +class User(me.Document): + email = me.StringField(required=True) + first_name = me.StringField(max_length=50) + last_name = me.StringField(max_length=50) + + def __repr__(self): + return ("".format(self.first_name, + self.last_name, + self.email)) + + +conn = me.connect('test') +print(conn) + +# Создаем документ +ross = User(email='ross@example.com', + first_name='Ross', + last_name='Lawley') +ross.save() +print('Документов в базе: {}'.format(User.objects.count())) + +# Делаем запрос +for i in range(5): + User(email='test@example.com', + first_name='User'+str(i), + last_name='Test').save() +print(User.objects.filter(first_name='User3')) +# Двойное нижнее подчеркивание используется для +# задания регулярного выражения +print(User.objects.filter(first_name__startswith='User')) + +# Удаляем запись в базе данных +User.objects(first_name__startswith='User').delete() +print('Документов в базе: {}'.format(User.objects.count())) + +# Удаляем все записи в базе данных +User.objects.delete() \ No newline at end of file diff --git a/Useful/for_lec20/publisher.py b/Useful/for_lec20/publisher.py new file mode 100644 index 0000000..cab44fd --- /dev/null +++ b/Useful/for_lec20/publisher.py @@ -0,0 +1,4 @@ +import redis + +r = redis.Redis(host='localhost', port=6379, db=0) +r.publish('my-chat', 'user: Hello!') diff --git a/Useful/for_lec20/scylla_example.py b/Useful/for_lec20/scylla_example.py new file mode 100644 index 0000000..d73608b --- /dev/null +++ b/Useful/for_lec20/scylla_example.py @@ -0,0 +1,44 @@ +from cassandra.cluster import Cluster + + +def insert_users(id, username, fullname, regdate, status): + session.execute( + "INSERT INTO users (id, username, fullname, regdate, status) VALUES (%s, %s, %s, %s, %s)", + (id, username, fullname, regdate, status) + ) + +def select_users(id=None): + if id is None: + res = session.execute("SELECT * FROM users") + else: + res = session.execute("SELECT * FROM users WHERE id = %s", (id,)) + if res: + res = [item for item in res] + return res + +def update_user_status(new_status, id=None): + if id is None: + session.execute("UPDATE users SET status = %s", (new_status)) + else: + session.execute("UPDATE users SET status = %s WHERE id = %s", (new_status, id)) + +def delete_users(id=None): + if id is None: + res = session.execute("DELETE FROM users") + else: + res = session.execute("DELETE FROM users WHERE id = %s", (id,)) + + +cluster = Cluster(['127.0.0.1']) +session = cluster.connect('example') + +insert_users(1, 'ivanovi', 'Иван Иванов', '2020-01-01', 'Available') +insert_users(2, 'petrovp', 'Петр Петров', '2020-02-02', 'Busy') +insert_users(3, 'orlovi', 'Илья Орлов', '2020-03-03', 'Available') + +print(select_users()) +print(select_users(1)) +update_user_status('Busy', 1) +print(select_users(1)) +delete_users(3) +print(select_users()) diff --git a/Useful/for_lec20/subscriber.py b/Useful/for_lec20/subscriber.py new file mode 100644 index 0000000..fc08ced --- /dev/null +++ b/Useful/for_lec20/subscriber.py @@ -0,0 +1,10 @@ +import redis + +r = redis.Redis(host='localhost', port=6379, db=0) +p = r.pubsub(ignore_subscribe_messages=True) +p.subscribe('my-chat') +while True: + msg = p.get_message() + if msg: + print("p.get_message(): ", msg) + break diff --git a/Useful/for_lec21/check_myfile.py b/Useful/for_lec21/check_myfile.py new file mode 100644 index 0000000..16bf191 --- /dev/null +++ b/Useful/for_lec21/check_myfile.py @@ -0,0 +1,16 @@ +from unittest import mock +import myfile + + +# def mock_print(arg): +# mock_print.arg = arg +# +# +# myfile.print = mock_print +# myfile.mysum(10, 20) +# assert mock_print.arg == 30 + + +myfile.print = mock.Mock() +myfile.mysum(10, 20) +myfile.print.assert_called_once_with(30) diff --git a/Useful/for_lec21/cmd_manager/audit_manager.py b/Useful/for_lec21/cmd_manager/audit_manager.py new file mode 100644 index 0000000..c0fc488 --- /dev/null +++ b/Useful/for_lec21/cmd_manager/audit_manager.py @@ -0,0 +1,7 @@ +class AuditManager: + def add_call(self, *args, **kwargs): + pass + def add_result(self, *args, **kwargs): + pass + +audit_service = AuditManager() diff --git a/Useful/for_lec21/cmd_manager/cmd_manager.py b/Useful/for_lec21/cmd_manager/cmd_manager.py new file mode 100644 index 0000000..d03eaa4 --- /dev/null +++ b/Useful/for_lec21/cmd_manager/cmd_manager.py @@ -0,0 +1,19 @@ +class AuditManager: + def add_call(self, *args, **kwargs): + pass + def add_result(self, *args, **kwargs): + pass + + +audit_service = AuditManager() + + +class CmdManager: + def set_service(self, service): + self.service = service + self.service.start() + + def run_command(self, cmd): + audit_service.add_call(self.service.name, 'run', cmd) + result = self.service.run(cmd) + audit_service.add_result(self.service.name, 'run', result) diff --git a/Useful/for_lec21/cmd_manager/test_cmd_manager.py b/Useful/for_lec21/cmd_manager/test_cmd_manager.py new file mode 100644 index 0000000..c0e760c --- /dev/null +++ b/Useful/for_lec21/cmd_manager/test_cmd_manager.py @@ -0,0 +1,40 @@ +import cmd_manager +import unittest +import unittest.mock as mock + + +class TestCmdManager(unittest.TestCase): + + def test_cmd_manager(self): + cmd_mgr = cmd_manager.CmdManager() + + # Мы тестируем класс CmdManager, объект audit_service нас интересует + # постольку, поскольку к нему идут обращения от методов CmdManager. + # Эти обращения можно рассматривать как выходные данные тестируемого + # класса CmdManager. + with mock.patch('cmd_manager.audit_service') as audit_service_mock: + # Метод set_service объекта класса CmdManager принимает + # в качестве параметра объект service, о котором мы знаем только + # то, что у него есть атрибут name и метод run, который должен + # что-то возвращать. Подставим вместо service mock-объект. + service = mock.Mock() + service.name = 'MyService' + RESULT = 0 + service.run.return_value = RESULT + + cmd_mgr.set_service(service) + self.assertTrue(service.start.called) + + CMD = 'status' + cmd_mgr.run_command(CMD) + # Используем assert-методы mock-объекта, которым мы подменили + # audit_service + audit_service_mock.add_call.assert_called_once_with( + 'MyService', 'run', CMD) + service.run.assert_called_once_with(CMD) + audit_service_mock.add_result.assert_called_once_with( + 'MyService', 'run', RESULT) + + +if __name__ == '__main__': + unittest.main() diff --git a/Useful/for_lec21/cmd_manager/test_cmd_manager_2.py b/Useful/for_lec21/cmd_manager/test_cmd_manager_2.py new file mode 100644 index 0000000..9e1dfa5 --- /dev/null +++ b/Useful/for_lec21/cmd_manager/test_cmd_manager_2.py @@ -0,0 +1,27 @@ +import cmd_manager +import unittest +import unittest.mock as mock + + +class TestCmdManager(unittest.TestCase): + + @mock.patch('cmd_manager.audit_service') + def test_cmd_manager(self, audit_service_mock): + cmd_mgr = cmd_manager.CmdManager() + service = mock.Mock() + service.name = 'MyService' + service.run.return_value = 0 + cmd_mgr.set_service(service) + self.assertTrue(service.start.called) + cmd_mgr.run_command('status') + # Используем assert-методы mock-объекта, которым мы подменили + # audit_service + audit_service_mock.add_call.assert_called_once_with('MyService', + 'run', 'status') + service.run.assert_called_once_with('status') + audit_service_mock.add_result.assert_called_once_with('MyService', + 'run', 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/Useful/for_lec21/example/.coverage b/Useful/for_lec21/example/.coverage new file mode 100644 index 0000000..ab6f96d Binary files /dev/null and b/Useful/for_lec21/example/.coverage differ diff --git a/Useful/for_lec21/example/my_ops.py b/Useful/for_lec21/example/my_ops.py new file mode 100644 index 0000000..f77a26d --- /dev/null +++ b/Useful/for_lec21/example/my_ops.py @@ -0,0 +1,6 @@ +def my_sum(a, b): + return a + b + + +def my_dif(a, b): + return a - b \ No newline at end of file diff --git a/Useful/for_lec21/example/myfile.py b/Useful/for_lec21/example/myfile.py new file mode 100644 index 0000000..23facc6 --- /dev/null +++ b/Useful/for_lec21/example/myfile.py @@ -0,0 +1,2 @@ +def fun(a, b): + return a + b \ No newline at end of file diff --git a/Useful/for_lec21/example/tasks.py b/Useful/for_lec21/example/tasks.py new file mode 100644 index 0000000..6798371 --- /dev/null +++ b/Useful/for_lec21/example/tasks.py @@ -0,0 +1,23 @@ +def mylen(list_arg): + res = 0 + for _ in list_arg: + res += 1 + return res + + +def myrange(start=0, stop=None, step=1): + if not stop: + stop = start + start = 0 + if step == 0: + f = lambda a, b: False + elif step > 0: + f = lambda a, b: a < b + else: + f = lambda a, b: a > b + i = start + l = [] + while f(i, stop): + l.append(i) + i += step + return l diff --git a/Useful/for_lec21/example/test_my_ops.py b/Useful/for_lec21/example/test_my_ops.py new file mode 100644 index 0000000..d590493 --- /dev/null +++ b/Useful/for_lec21/example/test_my_ops.py @@ -0,0 +1,33 @@ +import pytest +import my_ops + + +class TestMySum: + @pytest.fixture( + scope='function', + params=[(10, 20, 30), (-10, -20, -30), (10, 0, 10), (10, -10, 0)], + ids=lambda args: f"Test fun with args: {args}" + ) + def parametrize_sum(self, request): + return request.param + + def test_my_sum(self, parametrize_sum): + arg1, arg2, expected = parametrize_sum + res = my_ops.my_sum(arg1, arg2) + assert(res, expected) + + +class TestMyDif: + @pytest.fixture( + scope='function', + params=[(10, 20, -20), (-10, -20, 10), (10, 0, 10), (10, -10, 20)], + ids=lambda args: f"Test fun with args: {args}" + ) + def parametrize_dif(self, request): + return request.param + + + def test_my_dif(self, parametrize_dif): + arg1, arg2, expected = parametrize_dif + res = my_ops.my_dif(arg1, arg2) + assert(res, expected) diff --git a/Useful/for_lec21/example/test_myfile.py b/Useful/for_lec21/example/test_myfile.py new file mode 100644 index 0000000..9b41b66 --- /dev/null +++ b/Useful/for_lec21/example/test_myfile.py @@ -0,0 +1,25 @@ +import pytest +from myfile import fun + + +class TestMyFile: + @pytest.fixture( + scope='function', + params=[(10, 20, 30), (-10, -20, -30), (10, 0, 10), (10, -10, 0)], + ids=lambda args: f"Test fun with args: {args}" + ) + def parametrizer(self, request): + return request.param + + def test_fun(self, parametrizer): + arg1, arg2, res = parametrizer + assert(fun(arg1, arg2) == res) + + # def test_fun_1(self): + # assert(fun(10, 20) == 30) + # + # def test_fun_2(self): + # assert(fun(-10, -20) == -30) + # + # def test_fun_3(self): + # assert(fun(10, 0) == 10) diff --git a/Useful/for_lec21/example/test_myrange.py b/Useful/for_lec21/example/test_myrange.py new file mode 100644 index 0000000..05f5a10 --- /dev/null +++ b/Useful/for_lec21/example/test_myrange.py @@ -0,0 +1,20 @@ +import pytest +from tasks import myrange + + +class TestMyrangeSuite: + @pytest.fixture( + scope='function', + params=[(0, 5), (10, 20), (10, 20, 3), (20, 10, -2), (20, 10, 0)], + ids=lambda args: f"Test with args: {args}" + ) + def parametrize_myrange(self, request): + return request.param + + def test_myrange(self, parametrize_myrange): + range_args = parametrize_myrange + assert myrange(*range_args) == list(range(*range_args)) + + +if __name__ == '__main__': + pytest.main() diff --git a/Useful/for_lec21/example/test_tasks.py b/Useful/for_lec21/example/test_tasks.py new file mode 100644 index 0000000..cbff4a2 --- /dev/null +++ b/Useful/for_lec21/example/test_tasks.py @@ -0,0 +1,19 @@ +import pytest +from tasks import mylen, myrange + + +class TestTasksSuite: + def test_mylen(self): + l = [1, 45, 32, 9] + assert(mylen(l) == 4) + + def test_myrange(self): + assert(myrange(5) == list(range(5))) + assert(myrange(10, 20) == list(range(10, 20))) + assert(myrange(10, 20, 3) == list(range(10, 20, 3))) + assert(myrange(20, 10, -2) == list(range(20, 10, -2))) + assert(myrange(20, 10, 0) == list(range(20, 10, 0))) + + +if __name__ == '__main__': + pytest.main() diff --git a/Useful/for_lec21/example/test_tasks_new.py b/Useful/for_lec21/example/test_tasks_new.py new file mode 100644 index 0000000..d027f79 --- /dev/null +++ b/Useful/for_lec21/example/test_tasks_new.py @@ -0,0 +1,24 @@ +import pytest +from tasks import mylen, myrange + + +class TestTasksSuite: + def test_mylen(self): + l = [1, 45, 32, 9] + assert(mylen(l) == 4) + + @pytest.fixture( + scope='function', + params=[5, 10, 2], + ids=lambda args: f"Test with args: {args}" + ) + def parametrizer(self, request): + return request.param + + def test_myrange(self, parametrizer): + args = parametrizer + assert(myrange(args) == list(range(args))) + + +if __name__ == '__main__': + pytest.main() diff --git a/Useful/for_lec21/listener_mock_example.py b/Useful/for_lec21/listener_mock_example.py new file mode 100644 index 0000000..e596213 --- /dev/null +++ b/Useful/for_lec21/listener_mock_example.py @@ -0,0 +1,43 @@ +import unittest.mock as mock + + +# Тестируемый класс +class Listener: + def __init__(self): + self.running = True + + def listen_forever(self): + while self.running: + try: + msg = msg_broker.wait_message() + client.process_message(msg) + except Exception: + self.running = False + +# Подготовка к тестированию +# Создаем объект тестируемого класса +listener = Listener() + +# Заменяем зависимости на mock-объекты +msg_broker = mock.Mock() +client = mock.Mock() + +# Настраиваем поведение mock-объектов +# При инициализации атрибута side_effect итерируемым объектом +# при каждом обращении к wait_message будет возвращаться очередной +# элемент итерируемого объекта (сначала 'message', затем Exception). +msg_broker.wait_message.side_effect = ['message', Exception] + +def check_msg(msg): + assert msg == 'message' + +# При инициализации атрибута side_effect функциональным (callable) +# объектом при каждом обращении к process_message будет вызываться +# этот функциональный объект. +client.process_message.side_effect = check_msg + +# Тестируем и выполняем проверки +listener.listen_forever() +assert listener.running is False +client.process_message.assert_called_once_with('message') +assert msg_broker.wait_message.call_count == 2 diff --git a/Useful/for_lec21/mock_example.py b/Useful/for_lec21/mock_example.py new file mode 100644 index 0000000..172f00c --- /dev/null +++ b/Useful/for_lec21/mock_example.py @@ -0,0 +1,26 @@ +def fun(a, b): + print((a + b) * 100) + + +def mock_print(arg): + mock_print.arg = arg + + +class CtxMgr: + def __enter__(self): + global print + self.bkp_print = print + print = mock_print + def __exit__(self, exc_type, exc_val, exc_tb): + global print + print = self.bkp_print + + +with CtxMgr(): + fun(1, 2) + + +assert(mock_print.arg == 300) +print(mock_print.arg) + + diff --git a/Useful/for_lec21/mock_simple_example.py b/Useful/for_lec21/mock_simple_example.py new file mode 100644 index 0000000..e0f03f8 --- /dev/null +++ b/Useful/for_lec21/mock_simple_example.py @@ -0,0 +1,16 @@ +import unittest.mock as mock + + +def fun(service): + service.show() + service.name = "Hello" + s = service.get() + return s + + +m = mock.Mock() +m.get.return_value = 100 +res = fun(m) +assert(m.show.called is True) +assert(res == 100) + diff --git a/Useful/for_lec21/myfile.py b/Useful/for_lec21/myfile.py new file mode 100644 index 0000000..b2d14b0 --- /dev/null +++ b/Useful/for_lec21/myfile.py @@ -0,0 +1,4 @@ +def mysum(a, b): + print(a + b) + + diff --git a/Useful/for_lec21/pytest_useful_options.txt b/Useful/for_lec21/pytest_useful_options.txt new file mode 100644 index 0000000..9d88a1a --- /dev/null +++ b/Useful/for_lec21/pytest_useful_options.txt @@ -0,0 +1,8 @@ +# pip install pytest-html - для генерации красивых отчетов +# полезные опции pytest +pytest - запуск всех тестов (файлов test_.*.py) по порядку +pytest -p no:warnings - запуск тестов с отключенными warnings +pytest --cov-report html:cov_html --cov ../../папка_с_исходниками - запуск тестов с формированием отчета о покрытии тестами модулей ядра. +pytest --html=report.html --self-contained-html - запуск тестов с формированием self-contained html-отчета. +pytest -s - отображение текущих логов во время теста (иначе логи будут доступны только после окончания теста). +pytest test_tasks.py::TestTasksSuite:: - запуск конкретного теста \ No newline at end of file diff --git a/Useful/for_lec21/simple_examples/report.html b/Useful/for_lec21/simple_examples/report.html new file mode 100644 index 0000000..89e1921 --- /dev/null +++ b/Useful/for_lec21/simple_examples/report.html @@ -0,0 +1,615 @@ + + + + + Test Report + + + +

report.html

+

Report generated on 20-Oct-2022 at 20:52:34 by pytest-html v3.1.1

+

Environment

+ + + + + + + + + + + + +
Packages{"pluggy": "1.0.0", "py": "1.11.0", "pytest": "6.2.5"}
PlatformWindows-10-10.0.19041-SP0
Plugins{"cov": "3.0.0", "html": "3.1.1", "metadata": "2.0.2"}
Python3.7.9
+

Summary

+

12 tests ran in 0.37 seconds.

+ 10 passed, 2 skipped, 2 failed, 0 errors, 0 expected failures, 0 unexpected passes +

Results

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ResultTestDurationLinks
Failedtest_my_fun.py::TestMylen::test_mylen20.00
+
self = <test_my_fun.TestMylen testMethod=test_mylen2>

def test_mylen2(self):
> self.fail()
E AssertionError: None

test_my_fun.py:23: AssertionError
------------------------------Captured stdout call------------------------------
Before test +After test +
----------------------------Captured stdout teardown----------------------------
After test suite +
Failedtest_string_methods.py::TestStringMethods::test_upper0.00
+
self = <test_string_methods.TestStringMethods testMethod=test_upper>

def test_upper(self):
> self.assertEqual('foo'.upper(), 'FOo')
E AssertionError: 'FOO' != 'FOo'
E - FOO
E ? ^
E + FOo
E ? ^

test_string_methods.py:21: AssertionError
------------------------------Captured stdout call------------------------------
start +end +
----------------------------Captured stdout teardown----------------------------
class end +
Skippedtest_skip.py::MyTestCase::test_format0.00
+
('C:\\Users\\Stmadm\\Documents\\PythonCourseProject2\\PythonCourse2.0_August22\\Useful\\for_lec21\\simple_examples\\test_skip.py', 10, 'Skipped: not supported in this python version')
Skippedtest_skip.py::MyTestCase::test_nothing0.00
+
('C:\\Users\\Stmadm\\Documents\\PythonCourseProject2\\PythonCourse2.0_August22\\Useful\\for_lec21\\simple_examples\\test_skip.py', 6, 'Skipped: demonstrating skipping')
Passedtest_my_fun.py::TestMylen::test_mylen0.00
+
-----------------------------Captured stdout setup------------------------------
Before test suite +
------------------------------Captured stdout call------------------------------
Before test +After test +
Passedtest_skip.py::MyTestCase::test_windows_support0.00
+
No log output captured.
Passedtest_string_methods.py::TestStringMethods::test_isupper0.00
+
-----------------------------Captured stdout setup------------------------------
class start +
------------------------------Captured stdout call------------------------------
start +end +
Passedtest_string_methods.py::TestStringMethods::test_split0.00
+
------------------------------Captured stdout call------------------------------
start +end +
Passedtest_with_nose.py::TestWithNose::test_numbers_5_60.00
+
-----------------------------Captured stdout setup------------------------------
Before test suite +Before test case +
----------------------------Captured stdout teardown----------------------------
After test case +
Passedtest_with_nose.py::TestWithNose::test_strings_b_20.00
+
-----------------------------Captured stdout setup------------------------------
Before test case +
----------------------------Captured stdout teardown----------------------------
After test case +
Passedtest_with_nose.py::TestWithNose::test_zero_division0.00
+
-----------------------------Captured stdout setup------------------------------
Before test case +
----------------------------Captured stdout teardown----------------------------
After test case +After test suite +
Passedtest_with_pytest.py::TestWithPytestSuite::test_numbers_5_60.00
+
-----------------------------Captured stdout setup------------------------------
Before test suite +Before test case +
----------------------------Captured stdout teardown----------------------------
After test case +
Passedtest_with_pytest.py::TestWithPytestSuite::test_strings_b_20.00
+
-----------------------------Captured stdout setup------------------------------
Before test case +
----------------------------Captured stdout teardown----------------------------
After test case +
Passedtest_with_pytest.py::TestWithPytestSuite::test_zero_division0.00
+
-----------------------------Captured stdout setup------------------------------
Before test case +
----------------------------Captured stdout teardown----------------------------
After test case +After test suite +
\ No newline at end of file diff --git a/Useful/for_lec21/simple_examples/test_listener.py b/Useful/for_lec21/simple_examples/test_listener.py new file mode 100644 index 0000000..9ee12b3 --- /dev/null +++ b/Useful/for_lec21/simple_examples/test_listener.py @@ -0,0 +1,40 @@ +import unittest.mock as mock + +# Тестируемый класс +class Listener: + def __init__(self): + self.running = True + + def listen_forever(self): + while self.running: + try: + msg = msg_broker.wait_message() + client.process_message(msg) + except Exception: + self.running = False + +# Подготовка к тестированию +# Создаем объект тестируемого класса +listener = Listener() +# Заменяем зависимости на mock-объекты +msg_broker = mock.Mock() +client = mock.Mock() +# Настраиваем поведение mock-объектов +# При инициализации атрибута side_effect итерируемым объектом +# при каждом обращении к wait_message будет возвращаться очередной +# элемент итерируемого объекта. +MSG = 'message' +msg_broker.wait_message.side_effect = [MSG, Exception] + +def check_msg(msg): + assert msg == MSG +# При инициализации атрибута side_effect функциональным (callable) +# объектом при каждом обращении к process_message будет вызываться +# этот функциональный объект. +client.process_message.side_effect = check_msg + +# Тестируем и выполняем проверки +listener.listen_forever() +assert listener.running == False +client.process_message.assert_called_once_with('message') +assert msg_broker.wait_message.call_count == 2 \ No newline at end of file diff --git a/Useful/for_lec21/simple_examples/test_my_fun.py b/Useful/for_lec21/simple_examples/test_my_fun.py new file mode 100644 index 0000000..9ff7fc2 --- /dev/null +++ b/Useful/for_lec21/simple_examples/test_my_fun.py @@ -0,0 +1,23 @@ +from unittest import TestCase + + +class TestMylen(TestCase): + @classmethod + def setUpClass(cls): + print("Before test suite") + + @classmethod + def tearDownClass(cls): + print("After test suite") + + def setUp(self): + print("Before test") + + def tearDown(self): + print("After test") + + def test_mylen(self): + pass + + def test_mylen2(self): + self.fail() diff --git a/Useful/for_lec21/simple_examples/test_skip.py b/Useful/for_lec21/simple_examples/test_skip.py new file mode 100644 index 0000000..803d23c --- /dev/null +++ b/Useful/for_lec21/simple_examples/test_skip.py @@ -0,0 +1,18 @@ +import unittest +import sys + + +class MyTestCase(unittest.TestCase): + @unittest.skip("demonstrating skipping") + def test_nothing(self): + self.fail("shouldn't happen") + + @unittest.skipIf(sys.version_info.minor != 6, "not supported in this python version") + def test_format(self): + # Tests that work for only a certain version of the library. + pass + + @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") + def test_windows_support(self): + # windows specific testing code + pass diff --git a/Useful/for_lec21/simple_examples/test_string_methods.py b/Useful/for_lec21/simple_examples/test_string_methods.py new file mode 100644 index 0000000..61d6d5f --- /dev/null +++ b/Useful/for_lec21/simple_examples/test_string_methods.py @@ -0,0 +1,35 @@ +import unittest + + +class TestStringMethods(unittest.TestCase): + + def setUp(self): + print('start') + + def tearDown(self): + print('end') + + @classmethod + def setUpClass(cls): + print('class start') + + @classmethod + def tearDownClass(cls): + print('class end') + + def test_upper(self): + self.assertEqual('foo'.upper(), 'FOO') + + def test_isupper(self): + self.assertTrue('FOO'.isupper()) + self.assertFalse('Foo'.isupper()) + + def test_split(self): + s = 'hello world' + self.assertEqual(s.split(), ['hello', 'world']) + with self.assertRaises(TypeError): + s.split(2) + + +if __name__ == '__main__': + unittest.main() diff --git a/Useful/for_lec21/simple_examples/test_with_nose.py b/Useful/for_lec21/simple_examples/test_with_nose.py new file mode 100644 index 0000000..0b6ab82 --- /dev/null +++ b/Useful/for_lec21/simple_examples/test_with_nose.py @@ -0,0 +1,27 @@ +from nose.tools import assert_equals, raises + + +class TestWithNose: + def setup(self): + print('Before test case') + + def teardown(self): + print('After test case') + + @classmethod + def setup_class(cls): + print('Before test suite') + + @classmethod + def teardown_class(cls): + print('After test suite') + + def test_numbers_5_6(self): + assert_equals(5 * 6, 30) + + def test_strings_b_2(self): + assert_equals('b' * 2, 'bb') + + @raises(ZeroDivisionError) + def test_zero_division(self): + a = 10 / 0 diff --git a/Useful/for_lec21/simple_examples/test_with_pytest.py b/Useful/for_lec21/simple_examples/test_with_pytest.py new file mode 100644 index 0000000..e222e7a --- /dev/null +++ b/Useful/for_lec21/simple_examples/test_with_pytest.py @@ -0,0 +1,27 @@ +import pytest + + +class TestWithPytestSuite: + def setup(self): + print('Before test case') + + def teardown(self): + print('After test case') + + @classmethod + def setup_class(cls): + print('Before test suite') + + @classmethod + def teardown_class(cls): + print('After test suite') + + def test_numbers_5_6(self): + assert(5 * 6 == 30) + + def test_strings_b_2(self): + assert('b' * 2 == 'bb') + + def test_zero_division(self): + with pytest.raises(ZeroDivisionError): + a = 10 / 0 diff --git a/Useful/for_lec21/system_tests/check_selenium.py b/Useful/for_lec21/system_tests/check_selenium.py new file mode 100644 index 0000000..f927aa4 --- /dev/null +++ b/Useful/for_lec21/system_tests/check_selenium.py @@ -0,0 +1,29 @@ +import os +from selenium import webdriver +from selenium.common.exceptions import TimeoutException +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.by import By + + +os.environ['PATH'] += os.pathsep + r'C:\Soft\ForPython\chromedriver-win64' + +driver = webdriver.Chrome() + +driver.get('http://www.google.com') + +print(driver.title) + +inputElement = driver.find_element(by=By.NAME, value='q') + +inputElement.send_keys('cheese!') + +inputElement.submit() + +try: + WebDriverWait(driver, 10).until(EC.title_contains('cheese!')) + print(driver.title) +except TimeoutException: + print('Timeout exception!') +finally: + driver.quit() diff --git a/Useful/for_lec21/system_tests/copy_file_task.py b/Useful/for_lec21/system_tests/copy_file_task.py new file mode 100644 index 0000000..4448bb5 --- /dev/null +++ b/Useful/for_lec21/system_tests/copy_file_task.py @@ -0,0 +1,11 @@ +import os + + +def copyfile(source, destination): + with open(source, 'r') as src: + with open(destination, 'x') as dst: + dst.writelines(src.readlines()) + + +if __name__ == '__main__': + copyfile('source.txt', 'destination.txt') diff --git a/Useful/for_lec21/system_tests/log.html b/Useful/for_lec21/system_tests/log.html new file mode 100644 index 0000000..1019e52 --- /dev/null +++ b/Useful/for_lec21/system_tests/log.html @@ -0,0 +1,2199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Opening Robot Framework log failed

+
    +
  • Verify that you have JavaScript enabled in your browser.
  • +
  • Make sure you are using a modern enough browser. If using Internet Explorer, version 11 is required.
  • +
  • Check are there messages in your browser's JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Useful/for_lec21/system_tests/output.xml b/Useful/for_lec21/system_tests/output.xml new file mode 100644 index 0000000..b8b6adf --- /dev/null +++ b/Useful/for_lec21/system_tests/output.xml @@ -0,0 +1,117 @@ + + + + + +http://www.google.com +chrome +options=add_experimental_option("excludeSwitches", ["enable-logging"]) +Opens a new browser instance to the optional ``url``. +Arguments: [ 'http://www.google.com' | 'chrome' | options='add_experimental_option("excludeSwitches", ["enable-logging"])' ] +Opening browser 'chrome' to base url 'http://www.google.com'. +Started executable: `C:\Soft\ForPython\chromedriver-win64\chromedriver.EXE` in a child process with pid: 14208 +POST http://localhost:62820/session {"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "chrome", "pageLoadStrategy": "normal", "goog:chromeOptions": {"excludeSwitches": ["enable-logging"], "extensions": [], "args": []}}}} +Starting new HTTP connection (1): localhost:62820 +http://localhost:62820 "POST /session HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":{"capabilities":{"acceptInsecureCerts":false,"browserName":"chrome","browserVersion":"115.0.5790.110","chrome":{"chromedriverVersion":"115.0.5790.102 (90efd4b0ad6aa15eeafcdabd5817ae939f7ba059-refs/branch-heads/5790_90@{#9})","userDataDir":"C:\\Users\\Stmadm\\AppData\\Local\\Temp\\scoped_dir14208_980171044"},"goog:chromeOptions":{"debuggerAddress":"localhost:62823"},"networkConnectionEnabled":false,"pageLoadStrategy":"normal","platformName":"windows","proxy":{},"setWindowRect":true,"strictFileInteractability":false,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000},"unhandledPromptBehavior":"dismiss and notify","webauthn:extension:credBlob":true,"webauthn:extension:largeBlob":true,"webauthn:extension:minPinLength":true,"webauthn:extension:prf":true,"webauthn:virtualAuthenticators":true},"sessionId":"34371a5177e30e6abee2f1c95be64260"}} | headers=HTTPHeaderDict({'Content-Length': '862', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/timeouts {"script": 5000} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/timeouts HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/timeouts {"implicit": 0} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/timeouts HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/timeouts {"pageLoad": 300000} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/timeouts HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/url {"url": "http://www.google.com"} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/url HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +Opened browser with session id 34371a5177e30e6abee2f1c95be64260. +Return: 1 + + + +name=q +Cheese! +Types the given ``text`` into the text field identified by ``locator``. +Arguments: [ 'name=q' | 'Cheese!' ] +Typing text 'Cheese!' into text field 'name=q'. +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/elements {"using": "css selector", "value": "[name=\"q\"]"} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/elements HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":[{"element-6066-11e4-a52e-4f735466cecf":"6502A84DD8CC453C9B0E9D8AB0B58A46_element_2"}]} | headers=HTTPHeaderDict({'Content-Length': '96', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/element/6502A84DD8CC453C9B0E9D8AB0B58A46_element_2/clear {"id": "6502A84DD8CC453C9B0E9D8AB0B58A46_element_2"} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/element/6502A84DD8CC453C9B0E9D8AB0B58A46_element_2/clear HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/element/6502A84DD8CC453C9B0E9D8AB0B58A46_element_2/value {"text": "Cheese!", "value": ["C", "h", "e", "e", "s", "e", "!"], "id": "6502A84DD8CC453C9B0E9D8AB0B58A46_element_2"} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/element/6502A84DD8CC453C9B0E9D8AB0B58A46_element_2/value HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +Return: None + + + +Submits a form identified by ``locator``. +Arguments: [ ] +Submitting form 'None'. +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/elements {"using": "tag name", "value": "form"} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/elements HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":[{"element-6066-11e4-a52e-4f735466cecf":"6502A84DD8CC453C9B0E9D8AB0B58A46_element_18"}]} | headers=HTTPHeaderDict({'Content-Length': '97', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +GET http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/element/6502A84DD8CC453C9B0E9D8AB0B58A46_element_18/name {"id": "6502A84DD8CC453C9B0E9D8AB0B58A46_element_18"} +http://localhost:62820 "GET /session/34371a5177e30e6abee2f1c95be64260/element/6502A84DD8CC453C9B0E9D8AB0B58A46_element_18/name HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":"form"} | headers=HTTPHeaderDict({'Content-Length': '16', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +POST http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/execute/sync {"script": "/* submitForm */var form = arguments[0];\nwhile (form.nodeName != \"FORM\" && form.parentNode) {\n form = form.parentNode;\n}\nif (!form) { throw Error('Unable to find containing form element'); }\nif (!form.ownerDocument) { throw Error('Unable to find owning document'); }\nvar e = form.ownerDocument.createEvent('Event');\ne.initEvent('submit', true, true);\nif (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n", "args": [{"element-6066-11e4-a52e-4f735466cecf": "6502A84DD8CC453C9B0E9D8AB0B58A46_element_18"}]} +http://localhost:62820 "POST /session/34371a5177e30e6abee2f1c95be64260/execute/sync HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +Return: None + + + +10s +2s +Title Should Be +Cheese! - Поиск в Google +Runs the specified keyword and retries if it fails. +Arguments: [ '10s' | '2s' | 'Title Should Be' | 'Cheese! - Поиск в Google' ] + +Cheese! - Поиск в Google +Verifies that the current page title equals ``title``. +Arguments: [ 'Cheese! - Поиск в Google' ] +GET http://localhost:62820/session/34371a5177e30e6abee2f1c95be64260/title {} +http://localhost:62820 "GET /session/34371a5177e30e6abee2f1c95be64260/title HTTP/1.1" 200 0 +Remote response: status=200 | data={"value":"Cheese! - Поиск в Google"} | headers=HTTPHeaderDict({'Content-Length': '42', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) +Finished Request +Page title is 'Cheese! - Поиск в Google'. +Return: None + + +Return: None + + + + +Test google search + + + + +All Tests + + + + +Test Robot Sellib + + + + + diff --git a/Useful/for_lec21/system_tests/report.html b/Useful/for_lec21/system_tests/report.html new file mode 100644 index 0000000..970f905 --- /dev/null +++ b/Useful/for_lec21/system_tests/report.html @@ -0,0 +1,2462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Opening Robot Framework report failed

+
    +
  • Verify that you have JavaScript enabled in your browser.
  • +
  • Make sure you are using a modern enough browser. If using Internet Explorer, version 11 is required.
  • +
  • Check are there messages in your browser's JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Useful/for_lec21/system_tests/test_copy_file.robot b/Useful/for_lec21/system_tests/test_copy_file.robot new file mode 100644 index 0000000..32f60b3 --- /dev/null +++ b/Useful/for_lec21/system_tests/test_copy_file.robot @@ -0,0 +1,37 @@ +# Файл test_copy_file.robot + +*** Settings *** +Documentation Check file actions + +Library OperatingSystem + +Test Setup On Test Setup +Test Teardown On Test Teardown + + +*** Variables *** +${copy_script} python ./copy_file_task.py +${src_file} ./source.txt +${dst_file} ./destination.txt +${exp_content} hello + + +*** Keywords *** +On Test Setup + Create File ${src_file} ${exp_content} + File Should Exist ${src_file} + +On Test Teardown + Remove File ${src_file} + Remove File ${dst_file} + + +*** Test Cases *** +Test File Copy + [Documentation] Test file copy script + [Tags] DEBUG + File Should Not Exist ${dst_file} + Run ${copy_script} + File Should Exist ${dst_file} + ${content}= Get File ${dst_file} + Should Be True '${content}' == '${exp_content}' diff --git a/Useful/for_lec21/system_tests/test_robot_sellib.robot b/Useful/for_lec21/system_tests/test_robot_sellib.robot new file mode 100644 index 0000000..bb56930 --- /dev/null +++ b/Useful/for_lec21/system_tests/test_robot_sellib.robot @@ -0,0 +1,13 @@ +*** Settings *** +Documentation Test google search +Library SeleniumLibrary + + +*** Test Cases *** +Test Google Search + Open Browser http://www.google.com chrome options=add_experimental_option("excludeSwitches", ["enable-logging"]) + # Open Browser http://www.google.com chrome + Input Text name=q Cheese! + Submit Form + Wait Until Keyword Succeeds 10s 2s + ... Title Should Be Cheese! - Поиск в Google diff --git a/Useful/for_lec21/test_listener.py b/Useful/for_lec21/test_listener.py new file mode 100644 index 0000000..c6b5096 --- /dev/null +++ b/Useful/for_lec21/test_listener.py @@ -0,0 +1,36 @@ +import unittest.mock as mock +import listener_mock_example as lme + + +class TestListener: + MSG = 'message' + + @staticmethod + def check_msg(msg): + assert msg == TestListener.MSG + + def test_listen_forever(self): + # Подготовка к тестированию + # Создаем объект тестируемого класса + listener = lme.Listener() + + # Заменяем зависимости на mock-объекты + lme.Listener.msg_broker = mock.Mock() + lme.Listener.client = mock.Mock() + + # Настраиваем поведение mock-объектов + # При инициализации атрибута side_effect итерируемым объектом + # при каждом обращении к wait_message будет возвращаться очередной + # элемент итерируемого объекта (сначала 'message', затем Exception). + lme.Listener.msg_broker.wait_message.side_effect = [TestListener.MSG, Exception] + + # При инициализации атрибута side_effect функциональным (callable) + # объектом при каждом обращении к process_message будет вызываться + # этот функциональный объект. + lme.Listener.client.process_message.side_effect = TestListener.check_msg + + # Тестируем и выполняем проверки + listener.listen_forever() + assert listener.running is False + lme.Listener.client.process_message.assert_called_once_with(TestListener.MSG) + assert lme.Listener.msg_broker.wait_message.call_count == 2 diff --git a/Useful/for_lec22/kafka_example/consumer_example.py b/Useful/for_lec22/kafka_example/consumer_example.py new file mode 100644 index 0000000..0170163 --- /dev/null +++ b/Useful/for_lec22/kafka_example/consumer_example.py @@ -0,0 +1,57 @@ +import multiprocessing.pool as mp_pool +import kafka +import kafka.errors as kafka_errors + + +class LimitedMultiprocessingPool(mp_pool.Pool): + def get_pool_cache_size(self): + return len(self._cache) + + +class MsgConsumer: + def __init__(self, proc_fun): + # Функция для обработки сообщения в дочернем процессе + self.proc_fun = proc_fun + # Клиент для чтения сообщений из Kafka + self.consumer = kafka.KafkaConsumer( + "example_topic", + enable_auto_commit=False, + bootstrap_servers=["127.0.0.1:9092"], + group_id="example", + client_id="example-backend", + ) + # Лимит на количество сообщений, единовременно находящихся в пуле + self.pool_cache_limit = 20 + # Флаг управляемой остановки приложения + self.stop_processing = False + # Пул обработчиков сообщений + self.pool = LimitedMultiprocessingPool(processes=10) + + def handle_pool_cache_excess(self): + while self.pool.get_pool_cache_size() >= self.pool_cache_limit: + # Здесь можно предусмотреть sleep + pass + + def main_loop(self): + while not self.stop_processing: + for msg in self.consumer: + if self.stop_processing: + break + try: + self.handle_pool_cache_excess() + self.consumer.commit() + except kafka_errors.CommitFailedError: + # Отлавливаем редкий, но возможный случай исключения при ребалансе + continue + self.pool.apply_async(self.proc_fun, (msg,)) + + +def fun(*args, **kwargs): + print(f"Received from Kafka: {args}") + for arg in args: + print(f"Received value: {getattr(arg, 'value').decode()}") + + +if __name__ == "__main__": + consumer = MsgConsumer(fun) + consumer.main_loop() diff --git a/Useful/for_lec22/kafka_example/full_consumer_example.py b/Useful/for_lec22/kafka_example/full_consumer_example.py new file mode 100644 index 0000000..51d989a --- /dev/null +++ b/Useful/for_lec22/kafka_example/full_consumer_example.py @@ -0,0 +1,89 @@ +import multiprocessing as mp +import multiprocessing.pool as mp_pool +import signal +import time +import kafka +import kafka.errors as kafka_errors + + +class LimitedMultiprocessingPool(mp_pool.Pool): + def get_pool_cache_size(self): + return len(self._cache) + + +class MsgConsumer: + def __init__(self, proc_fun): + # Функция для обработки сообщения в дочернем процессе + self.proc_fun = proc_fun + # Клиент для чтения сообщений из Kafka + self.consumer = kafka.KafkaConsumer( + "labeling", + auto_offset_reset="earliest", + enable_auto_commit=False, + bootstrap_servers=["127.0.0.1:9092"], + group_id="labeling", + client_id="labeling-backend", + check_crcs="false", + consumer_timeout_ms=1000, + session_timeout_ms=30000, + request_timeout_ms=30500, + max_partition_fetch_bytes=2000000000 + ) + # Лимит на количество сообщений, единовременно находящихся в пуле + self.pool_cache_limit = 20 + self.graceful_shutdown_timeout = 600 + # Флаг управляемой остановки приложения + self.stop_processing = False + # Пул обработчиков сообщений + self.pool = LimitedMultiprocessingPool(processes=10) + # Обеспечиваем возможность остановки приложения по SIGTERM + signal.signal(signal.SIGTERM, self.set_stop_processing) + + def set_stop_processing(self, *args, **kwargs): + self.stop_processing = True + + def handle_pool_cache_excess(self): + while self.pool.get_pool_cache_size() >= self.pool_cache_limit: + # Здесь можно предусмотреть sleep + pass + + def main_loop(self): + while not self.stop_processing: + for msg in self.consumer: + if self.stop_processing: + break + try: + self.handle_pool_cache_excess() + self.consumer.commit() + except kafka_errors.CommitFailedError: + # Отлавливаем редкий, но возможный случай исключения при ребалансе + continue + self.pool.apply_async(self.proc_fun, (msg,)) + + def graceful_shutdown(self): + try: + self.consumer.close() # Останавливаем клиента Kafka + self.pool.close() # Предотвращаем добавление новых задач в пул + graceful_shutdown_end = time.time() + self.graceful_shutdown_timeout + while graceful_shutdown_end > time.time(): + active_child_proc_num = len(mp.active_children()) + if active_child_proc_num == 0: + break + # Здесь можно предусмотреть sleep + else: + raise + except Exception as ex: + self.pool.terminate() + raise ex + finally: + self.pool.join() + + +def fun(*args, **kwargs): + print("Do nothing") + + +if __name__ == "__main__": + consumer = MsgConsumer(fun) + consumer.main_loop() + consumer.graceful_shutdown() diff --git a/Useful/for_lec22/kafka_example/producer_example.py b/Useful/for_lec22/kafka_example/producer_example.py new file mode 100644 index 0000000..34bf279 --- /dev/null +++ b/Useful/for_lec22/kafka_example/producer_example.py @@ -0,0 +1,9 @@ +import kafka + + +if __name__ == "__main__": + producer = kafka.KafkaProducer(bootstrap_servers=["127.0.0.1:9092"]) + producer.send("example_topic", 'example_message_1'.encode()) + producer.send("example_topic", 'example_message_2'.encode()) + # Для немедленной отправки без буферизации + producer.flush() diff --git a/Useful/for_lec22/rabbit_example/publisher.py b/Useful/for_lec22/rabbit_example/publisher.py new file mode 100644 index 0000000..382cc46 --- /dev/null +++ b/Useful/for_lec22/rabbit_example/publisher.py @@ -0,0 +1,14 @@ +import pika + +connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + + +channel.exchange_declare(exchange='logs', exchange_type='topic') + +for i in range(5): + channel.basic_publish(exchange='logs', + routing_key='2.hello', + body=f'Hello World {i}'.encode()) +print("Sent 'Hello World!'") +connection.close() \ No newline at end of file diff --git a/Useful/for_lec22/rabbit_example/rec.py b/Useful/for_lec22/rabbit_example/rec.py new file mode 100644 index 0000000..7c26b0e --- /dev/null +++ b/Useful/for_lec22/rabbit_example/rec.py @@ -0,0 +1,20 @@ +import pika +import time +import random + +connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) +channel = connection.channel() +channel.queue_declare(queue='hello3', durable=True) + + +def callback(ch, method, properties, body): + print(f'Start processing {body.decode()}') + t = time.time() + time.sleep(random.randint(1, 5)) + print(f'Processed for {time.time() - t:.2f} sec.') + + +channel.basic_consume(queue='hello3', on_message_callback=callback, auto_ack=True) + +print('Waiting for messages. To exit press CTRL+C') +channel.start_consuming() diff --git a/Useful/for_lec22/rabbit_example/receiver.py b/Useful/for_lec22/rabbit_example/receiver.py new file mode 100644 index 0000000..d26d94d --- /dev/null +++ b/Useful/for_lec22/rabbit_example/receiver.py @@ -0,0 +1,29 @@ +# файл receive.py + +import pika +import time +import random + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + + +channel.queue_declare(queue='hello', durable=True) + + +def callback(ch, method, properties, body): + print('Start processing {}'.format(body.decode())) + t = time.time() + time.sleep(random.randint(1, 5)) + print(f'Processed for {time.time() - t:3.2f} sec.') + channel.basic_ack(delivery_tag=method.delivery_tag) + + +channel.basic_qos(prefetch_count=1) +channel.basic_consume(queue='hello', + on_message_callback=callback, + auto_ack=False) + +print('Waiting for messages. To exit press CTRL+C') +channel.start_consuming() \ No newline at end of file diff --git a/Useful/for_lec22/rabbit_example/send.py b/Useful/for_lec22/rabbit_example/send.py new file mode 100644 index 0000000..39d4cc8 --- /dev/null +++ b/Useful/for_lec22/rabbit_example/send.py @@ -0,0 +1,13 @@ +# файл send.py +import pika + +connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) +channel = connection.channel() +channel.queue_declare(queue='hello3', durable=True) + +for i in range(5): + channel.basic_publish(exchange='', routing_key='hello3', + body=f'Hello World {i}'.encode()) + +print("Sent 'Hello World!'") +connection.close() diff --git a/Useful/for_lec22/rabbit_example/sender.py b/Useful/for_lec22/rabbit_example/sender.py new file mode 100644 index 0000000..8a12860 --- /dev/null +++ b/Useful/for_lec22/rabbit_example/sender.py @@ -0,0 +1,15 @@ +import pika + +connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + + +channel.queue_declare(queue='hello', durable=True) + +for i in range(5): + channel.basic_publish(exchange='', + routing_key='hello', + body=f'Hello World {i}'.encode(), + properties=pika.BasicProperties(delivery_mode=2)) +print("Sent 'Hello World!'") +connection.close() \ No newline at end of file diff --git a/Useful/for_lec22/rabbit_example/subscriber1.py b/Useful/for_lec22/rabbit_example/subscriber1.py new file mode 100644 index 0000000..3eea55d --- /dev/null +++ b/Useful/for_lec22/rabbit_example/subscriber1.py @@ -0,0 +1,30 @@ +# файл receive.py + +import pika +import time +import random + +NAME = 'Logger 1' + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='logs', exchange_type='topic') +queue_name = 'hello_1' +result = channel.queue_declare(queue=queue_name, exclusive=True) +channel.queue_bind(exchange='logs', routing_key='*.hello', queue=queue_name) + + +def callback(ch, method, properties, body): + print(f'Processing msg {body.decode()} by: {NAME}') + channel.basic_ack(delivery_tag=method.delivery_tag) + + +channel.basic_qos(prefetch_count=1) +channel.basic_consume(queue=queue_name, + on_message_callback=callback, + auto_ack=False) + +print('Waiting for messages. To exit press CTRL+C') +channel.start_consuming() diff --git a/Useful/for_lec22/rabbit_example/subscriber2.py b/Useful/for_lec22/rabbit_example/subscriber2.py new file mode 100644 index 0000000..7434f4b --- /dev/null +++ b/Useful/for_lec22/rabbit_example/subscriber2.py @@ -0,0 +1,30 @@ +# файл receive.py + +import pika +import time +import random + +NAME = 'Logger 2' + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='logs', exchange_type='topic') +queue_name = 'hello_3' +result = channel.queue_declare(queue=queue_name, exclusive=False) +channel.queue_bind(exchange='logs', routing_key='*.bye', queue=queue_name) + + +def callback(ch, method, properties, body): + print(f'Processing msg {body.decode()} by: {NAME}') + channel.basic_ack(delivery_tag=method.delivery_tag) + + +channel.basic_qos(prefetch_count=1) +channel.basic_consume(queue=queue_name, + on_message_callback=callback, + auto_ack=False) + +print('Waiting for messages. To exit press CTRL+C') +channel.start_consuming() diff --git a/Useful/for_lec23/MVC_and_MTV.png b/Useful/for_lec23/MVC_and_MTV.png new file mode 100644 index 0000000..d4a5564 Binary files /dev/null and b/Useful/for_lec23/MVC_and_MTV.png differ diff --git a/Useful/for_lec23/coolapp/__init__.py b/Useful/for_lec23/coolapp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Useful/for_lec23/coolapp/admin.py b/Useful/for_lec23/coolapp/admin.py new file mode 100644 index 0000000..f4a53b7 --- /dev/null +++ b/Useful/for_lec23/coolapp/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from .models import Film + +# Register your models here. +admin.site.register(Film) diff --git a/Useful/for_lec23/coolapp/apps.py b/Useful/for_lec23/coolapp/apps.py new file mode 100644 index 0000000..a37f808 --- /dev/null +++ b/Useful/for_lec23/coolapp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CoolappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'coolapp' diff --git a/Useful/for_lec23/coolapp/forms.py b/Useful/for_lec23/coolapp/forms.py new file mode 100644 index 0000000..d13f03a --- /dev/null +++ b/Useful/for_lec23/coolapp/forms.py @@ -0,0 +1,9 @@ +from django import forms +from .models import Film + + +class FilmForm(forms.ModelForm): + class Meta: + model = Film + fields = ('name', 'desc', 'rate') +# поля pub_date и id заполняются сами diff --git a/Useful/for_lec23/coolapp/migrations/0001_initial.py b/Useful/for_lec23/coolapp/migrations/0001_initial.py new file mode 100644 index 0000000..d45ad69 --- /dev/null +++ b/Useful/for_lec23/coolapp/migrations/0001_initial.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.8 on 2022-02-28 17:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Film', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('desc', models.TextField()), + ('pub_date', models.DateTimeField(auto_now_add=True, verbose_name='date published')), + ], + ), + ] diff --git a/Useful/for_lec23/coolapp/migrations/0002_film_rate.py b/Useful/for_lec23/coolapp/migrations/0002_film_rate.py new file mode 100644 index 0000000..0411521 --- /dev/null +++ b/Useful/for_lec23/coolapp/migrations/0002_film_rate.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.8 on 2022-02-28 17:40 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('coolapp', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='film', + name='rate', + field=models.IntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(10)]), + ), + ] diff --git a/Useful/for_lec23/coolapp/migrations/__init__.py b/Useful/for_lec23/coolapp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Useful/for_lec23/coolapp/models.py b/Useful/for_lec23/coolapp/models.py new file mode 100644 index 0000000..f643ae6 --- /dev/null +++ b/Useful/for_lec23/coolapp/models.py @@ -0,0 +1,16 @@ +from django.db import models +from django.core.validators import MaxValueValidator, MinValueValidator + + +# Create your models here. +class Film(models.Model): + name = models.CharField(max_length=200) + desc = models.TextField() + pub_date = models.DateTimeField('date published', auto_now_add=True) + rate = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(10)], default=1) + + def __repr__(self): + return f"Film {self.name}" + + def __str__(self): + return f"Film {self.name} | Rate: {self.rate}" diff --git a/Useful/for_lec23/coolapp/static/css/main.css b/Useful/for_lec23/coolapp/static/css/main.css new file mode 100644 index 0000000..c1274c3 --- /dev/null +++ b/Useful/for_lec23/coolapp/static/css/main.css @@ -0,0 +1,3 @@ +html { + background-color: #faebd7; /* Цвет фона */ +} diff --git a/Useful/for_lec23/coolapp/templates/coolapp/base.html b/Useful/for_lec23/coolapp/templates/coolapp/base.html new file mode 100644 index 0000000..26c2ea3 --- /dev/null +++ b/Useful/for_lec23/coolapp/templates/coolapp/base.html @@ -0,0 +1,14 @@ + + +{% load static %} + + + + About films + + +

Site about films

+ {% block content %} + {% endblock %} + + diff --git a/Useful/for_lec23/coolapp/templates/coolapp/films.html b/Useful/for_lec23/coolapp/templates/coolapp/films.html new file mode 100644 index 0000000..f017fe7 --- /dev/null +++ b/Useful/for_lec23/coolapp/templates/coolapp/films.html @@ -0,0 +1,16 @@ +{% extends 'coolapp/base.html' %} +{% block content %} + +{% for film in films %} +

{{ film.name }}

+

{{ film.desc }}

+{% if film.pub_date %} +

Film date - {{ film.pub_date }}!

+{% else %} +

Film date - Unknown!

+{% endif %} +

{{ film.rate }}

+{% endfor %} + +{% endblock content %} + diff --git a/Useful/for_lec23/coolapp/templates/coolapp/index.html b/Useful/for_lec23/coolapp/templates/coolapp/index.html new file mode 100644 index 0000000..0aa9fcc --- /dev/null +++ b/Useful/for_lec23/coolapp/templates/coolapp/index.html @@ -0,0 +1,10 @@ + + + + + Title + + +

Hello everybody

+ + \ No newline at end of file diff --git a/Useful/for_lec23/coolapp/templates/coolapp/new.html b/Useful/for_lec23/coolapp/templates/coolapp/new.html new file mode 100644 index 0000000..23495c4 --- /dev/null +++ b/Useful/for_lec23/coolapp/templates/coolapp/new.html @@ -0,0 +1,9 @@ +{% extends 'coolapp/base.html' %} +{% block content %} + +

New film

+
{% csrf_token %} +{{ form.as_p }} +
+ +{% endblock content %} \ No newline at end of file diff --git a/Useful/for_lec23/coolapp/tests.py b/Useful/for_lec23/coolapp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/Useful/for_lec23/coolapp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/Useful/for_lec23/coolapp/urls.py b/Useful/for_lec23/coolapp/urls.py new file mode 100644 index 0000000..552ff09 --- /dev/null +++ b/Useful/for_lec23/coolapp/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from . import views + + +urlpatterns = [ + path('', views.index, name='index'), + path('new/', views.new, name='new'), + path('films/', views.films, name='films'), + path('/', views.new, name='new'), +] diff --git a/Useful/for_lec23/coolapp/views.py b/Useful/for_lec23/coolapp/views.py new file mode 100644 index 0000000..07d3a83 --- /dev/null +++ b/Useful/for_lec23/coolapp/views.py @@ -0,0 +1,28 @@ +from django.shortcuts import render +from .models import Film +from .forms import FilmForm +from django.shortcuts import redirect + + +def index(request): + return render(request, 'coolapp/index.html') + + +def films(request): + return render(request, 'coolapp/films.html', + {'films': Film.objects.all()}) + + +def new(request, film_id=None): + if request.method == "POST": + form = FilmForm(request.POST) + if form.is_valid(): + film = form.save() + return redirect(f'/{film.id}', film=film) + if film_id: + film = Film.objects.get(id=film_id) + else: + film = Film() + return render(request, 'coolapp/new.html', + {'form': FilmForm(instance=film)}) + diff --git a/Useful/for_lec23/coolsite/__init__.py b/Useful/for_lec23/coolsite/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Useful/for_lec23/coolsite/asgi.py b/Useful/for_lec23/coolsite/asgi.py new file mode 100644 index 0000000..b371d88 --- /dev/null +++ b/Useful/for_lec23/coolsite/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for coolsite project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coolsite.settings') + +application = get_asgi_application() diff --git a/Useful/for_lec23/coolsite/coolapp/__init__.py b/Useful/for_lec23/coolsite/coolapp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Useful/for_lec23/coolsite/coolapp/admin.py b/Useful/for_lec23/coolsite/coolapp/admin.py new file mode 100644 index 0000000..a048687 --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from .models import Film + +admin.site.register(Film) + diff --git a/Useful/for_lec23/coolsite/coolapp/apps.py b/Useful/for_lec23/coolsite/coolapp/apps.py new file mode 100644 index 0000000..a37f808 --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CoolappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'coolapp' diff --git a/Useful/for_lec23/coolsite/coolapp/forms.py b/Useful/for_lec23/coolsite/coolapp/forms.py new file mode 100644 index 0000000..0f2b48c --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/forms.py @@ -0,0 +1,8 @@ +from django import forms +from .models import Film + + +class FilmForm(forms.ModelForm): + class Meta: + model = Film + fields = ('name', 'desc', 'rate') diff --git a/Useful/for_lec23/coolsite/coolapp/migrations/0001_initial.py b/Useful/for_lec23/coolsite/coolapp/migrations/0001_initial.py new file mode 100644 index 0000000..656d6cc --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/migrations/0001_initial.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.8 on 2021-10-14 16:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Film', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('desc', models.TextField()), + ('pub_date', models.DateTimeField(auto_now_add=True, verbose_name='date published')), + ], + ), + ] diff --git a/Useful/for_lec23/coolsite/coolapp/migrations/0002_film_rate.py b/Useful/for_lec23/coolsite/coolapp/migrations/0002_film_rate.py new file mode 100644 index 0000000..e60042b --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/migrations/0002_film_rate.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.8 on 2021-10-14 17:10 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('coolapp', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='film', + name='rate', + field=models.IntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(10)]), + ), + ] diff --git a/Useful/for_lec23/coolsite/coolapp/migrations/__init__.py b/Useful/for_lec23/coolsite/coolapp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Useful/for_lec23/coolsite/coolapp/models.py b/Useful/for_lec23/coolsite/coolapp/models.py new file mode 100644 index 0000000..4361da5 --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/models.py @@ -0,0 +1,12 @@ +from django.db import models +from django.core.validators import MaxValueValidator, MinValueValidator + + +class Film(models.Model): + name = models.CharField(max_length=200) + desc = models.TextField() + pub_date = models.DateTimeField('date published', auto_now_add=True) + rate = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(10)], default=1) + + def __str__(self): + return f"{self.name}: {self.desc}" diff --git a/Useful/for_lec23/coolsite/coolapp/static/css/main.css b/Useful/for_lec23/coolsite/coolapp/static/css/main.css new file mode 100644 index 0000000..cd4b7eb --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/static/css/main.css @@ -0,0 +1,3 @@ +html { + background-color: #ffff00; /* Цвет фона */ +} diff --git a/Useful/for_lec23/coolsite/coolapp/templates/coolapp/base.html b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/base.html new file mode 100644 index 0000000..433b602 --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/base.html @@ -0,0 +1,15 @@ + +{% load static %} + + + + + About films + + +

Cool site

+

Table

+ {% block content %} + {% endblock %} + + diff --git a/Useful/for_lec23/coolsite/coolapp/templates/coolapp/films.html b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/films.html new file mode 100644 index 0000000..eca3715 --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/films.html @@ -0,0 +1,14 @@ +{% extends 'coolapp/base.html' %} +{% block content %} + +{% for film in films %} +

{{ film.name }}

+

{{ film.desc }}

+{% if film.pub_date %} +

Film date - {{ film.pub_date }}!

+{% else %} +

Film date - Unknown!

+{% endif %} +

{{ film.rate }}

+{% endfor %} +{% endblock content %} diff --git a/Useful/for_lec23/coolsite/coolapp/templates/coolapp/index.html b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/index.html new file mode 100644 index 0000000..ae3ae8c --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/index.html @@ -0,0 +1,4 @@ +{% extends 'coolapp/base.html' %} +{% block content %} +

Hello everybody!

+{% endblock content %} \ No newline at end of file diff --git a/Useful/for_lec23/coolsite/coolapp/templates/coolapp/new.html b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/new.html new file mode 100644 index 0000000..2d55c2b --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/templates/coolapp/new.html @@ -0,0 +1,7 @@ +{% extends 'coolapp/base.html' %} +{% block content %} +

New film

+
{% csrf_token %} +{{ form.as_p }} +
+{% endblock content %} \ No newline at end of file diff --git a/Useful/for_lec23/coolsite/coolapp/tests.py b/Useful/for_lec23/coolsite/coolapp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/Useful/for_lec23/coolsite/coolapp/urls.py b/Useful/for_lec23/coolsite/coolapp/urls.py new file mode 100644 index 0000000..cde630f --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/urls.py @@ -0,0 +1,11 @@ +from django.urls import path +from . import views + + +urlpatterns = [ + path('', views.index, name='index'), + path('bye', views.index2, name='index2'), + path('films/', views.films, name='films'), + path('new/', views.new, name='new'), + path('/', views.new, name='new'), +] diff --git a/Useful/for_lec23/coolsite/coolapp/views.py b/Useful/for_lec23/coolsite/coolapp/views.py new file mode 100644 index 0000000..1aa9c06 --- /dev/null +++ b/Useful/for_lec23/coolsite/coolapp/views.py @@ -0,0 +1,30 @@ +from django.shortcuts import render +from django.http import HttpResponse +from django.shortcuts import redirect +from .models import Film +from .forms import FilmForm + + +def index(request): + return render(request, 'coolapp/index.html') + + +def index2(request): + return HttpResponse("Пока!!!") + + +def films(request): + return render(request, 'coolapp/films.html', {'films': Film.objects.all()}) + + +def new(request, film_id=None): + if request.method == "POST": + form = FilmForm(request.POST) + if form.is_valid(): + film = form.save() + return redirect(f'/{film.id}', film=film) # http://127.0.0.1:8000/1 + if film_id: + film = Film.objects.get(id=film_id) + else: + film = Film() + return render(request, 'coolapp/new.html', {'form': FilmForm(instance=film)}) diff --git a/Useful/for_lec23/coolsite/coolsite/__init__.py b/Useful/for_lec23/coolsite/coolsite/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Useful/for_lec23/coolsite/coolsite/asgi.py b/Useful/for_lec23/coolsite/coolsite/asgi.py new file mode 100644 index 0000000..b371d88 --- /dev/null +++ b/Useful/for_lec23/coolsite/coolsite/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for coolsite project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coolsite.settings') + +application = get_asgi_application() diff --git a/Useful/for_lec23/coolsite/coolsite/settings.py b/Useful/for_lec23/coolsite/coolsite/settings.py new file mode 100644 index 0000000..847315c --- /dev/null +++ b/Useful/for_lec23/coolsite/coolsite/settings.py @@ -0,0 +1,128 @@ +""" +Django settings for coolsite project. + +Generated by 'django-admin startproject' using Django 3.2.8. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.2/ref/settings/ +""" + +from pathlib import Path +import os + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-3!gypw2h-deir9=mvsoyofzqvv&5%c^-iopf9qw$-nipu#7@vm' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'coolapp' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'coolsite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'coolsite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Europe/Moscow' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.2/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'static') + +# Default primary key field type +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/Useful/for_lec23/coolsite/coolsite/urls.py b/Useful/for_lec23/coolsite/coolsite/urls.py new file mode 100644 index 0000000..0f3453d --- /dev/null +++ b/Useful/for_lec23/coolsite/coolsite/urls.py @@ -0,0 +1,27 @@ +"""coolsite URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include + + +urlpatterns = [ + path('admin/', admin.site.urls), + path('coolapp/', include('coolapp.urls')), # path('coolapp/', coolapp.views.index) + path('', include('coolapp.urls')) # path('coolapp/', bye', coolapp.views.index2) +] + + + diff --git a/Useful/for_lec23/coolsite/coolsite/wsgi.py b/Useful/for_lec23/coolsite/coolsite/wsgi.py new file mode 100644 index 0000000..f938dff --- /dev/null +++ b/Useful/for_lec23/coolsite/coolsite/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for coolsite project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coolsite.settings') + +application = get_wsgi_application() diff --git a/Useful/for_lec23/coolsite/db.sqlite3 b/Useful/for_lec23/coolsite/db.sqlite3 new file mode 100644 index 0000000..f4b3ece Binary files /dev/null and b/Useful/for_lec23/coolsite/db.sqlite3 differ diff --git a/Useful/for_lec23/coolsite/manage.py b/Useful/for_lec23/coolsite/manage.py new file mode 100644 index 0000000..445748c --- /dev/null +++ b/Useful/for_lec23/coolsite/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coolsite.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/Useful/for_lec23/coolsite/settings.py b/Useful/for_lec23/coolsite/settings.py new file mode 100644 index 0000000..39453ad --- /dev/null +++ b/Useful/for_lec23/coolsite/settings.py @@ -0,0 +1,128 @@ +""" +Django settings for coolsite project. + +Generated by 'django-admin startproject' using Django 3.2.8. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.2/ref/settings/ +""" +import os +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-0&&x9i1z4cod!&t7k9_m1@ypc)i_1qn4qibbkk7c2r$8s=@isd' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'coolapp' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'coolsite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'coolsite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Europe/Moscow' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.2/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'static') + + +# Default primary key field type +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/Useful/for_lec23/coolsite/urls.py b/Useful/for_lec23/coolsite/urls.py new file mode 100644 index 0000000..71bb970 --- /dev/null +++ b/Useful/for_lec23/coolsite/urls.py @@ -0,0 +1,27 @@ +"""coolsite URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path +from django.conf.urls import include + + +urlpatterns = [ + path('admin/', admin.site.urls), + path('coolapp/', include('coolapp.urls')), + path('', include('coolapp.urls')), + # path('coolapp/', views.index, name='index'), + # path('coolapp/index', views.index, name='index'), +] diff --git a/Useful/for_lec23/coolsite/wsgi.py b/Useful/for_lec23/coolsite/wsgi.py new file mode 100644 index 0000000..f938dff --- /dev/null +++ b/Useful/for_lec23/coolsite/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for coolsite project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coolsite.settings') + +application = get_wsgi_application() diff --git a/Useful/for_lec23/db.sqlite3 b/Useful/for_lec23/db.sqlite3 new file mode 100644 index 0000000..a235376 Binary files /dev/null and b/Useful/for_lec23/db.sqlite3 differ diff --git a/Useful/for_lec23/example_tests/tcp_server.py b/Useful/for_lec23/example_tests/tcp_server.py new file mode 100644 index 0000000..741c29a --- /dev/null +++ b/Useful/for_lec23/example_tests/tcp_server.py @@ -0,0 +1,54 @@ +"""# Написать Unit-тесты для TCP-сервера (код см. далее), +# использовать mock, чтобы эмулировать действия клиента и создание потоков, +# получить code coverage репорт в html формате.""" + +import threading +import socket + + +class ClientThread(threading.Thread): + def __init__(self, conn, addr): + super().__init__() + self._connection = conn + self._address = addr + + def run(self): + print(f'Connection from address {self._address}') + data = self._connection.recv(1024) + print(f'Received {data.decode()}') + self._connection.send(data) + self._connection.close() + print(f'Closed connection from {self._address}') + + +class TcpServer: + def __init__(self, host, port): + self.host = host + self.port = port + self._socket = None + self._runnning = False + + def run(self): + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._socket.bind((self.host, self.port)) + self._socket.listen(5) + self._runnning = True + print('Server is up') + while self._runnning: + conn, addr = self._socket.accept() + ClientThread(conn, addr).start() + + def stop(self): + self._runnning = False + self._socket.close() + print('Server is down') + + +if __name__ == '__main__': + srv = TcpServer(host='127.0.0.1', port=5555) + try: + srv.run() + except KeyboardInterrupt: + srv.stop() + \ No newline at end of file diff --git a/Useful/for_lec23/example_tests/test_tcp_server.py b/Useful/for_lec23/example_tests/test_tcp_server.py new file mode 100644 index 0000000..d18e2d8 --- /dev/null +++ b/Useful/for_lec23/example_tests/test_tcp_server.py @@ -0,0 +1,48 @@ +"""Написать Unit-тесты для TCP-сервера (код см. далее), +использовать mock, чтобы эмулировать действия клиента и создание потоков, +получить code coverage репорт в html формате.""" + +import tcp_server +import unittest +from unittest import mock +from itertools import tee + + +class TestTcpServer(unittest.TestCase): + def test_tcpserver(self): + # Создаём объект тестируемого класса. + server = tcp_server.TcpServer(host='localhost', port=1234) + + # Заменяем зависимости на mock-объекты + tcp_server.socket = mock.Mock() + tcp_server.ClientThread = mock.Mock() + + # Настраиваем поведение mock-объекта socket.socket + socket_mock = mock.Mock() + hosts = [('ip1', 'port1'), ('ip2', 'port2'), ('ip3', 'port3'), StopIteration] + socket_mock.accept.side_effect = hosts + tcp_server.socket.socket.return_value = socket_mock + + # Настраиваем поведение mock-объекта tcp_server.ClientThread + def thread_start(): + ip, port = hosts[socket_mock.accept.call_count - 1] + print(f"New client connect - {ip}:{port}") + client_mock = mock.Mock() + client_mock.start.side_effect = thread_start + tcp_server.ClientThread.return_value = client_mock + + # Тестируем и выполняем проверки + try: + self.assertFalse(server._runnning) + server.run() + self.assertTrue(server._runnning) + except StopIteration: + server.stop() + self.assertFalse(server._runnning) + + assert socket_mock.accept.call_count == 4 + assert client_mock.start.call_count == 3 + + +if __name__ == '__main__': + unittest.main() diff --git a/Useful/for_lec23/manage.py b/Useful/for_lec23/manage.py new file mode 100644 index 0000000..445748c --- /dev/null +++ b/Useful/for_lec23/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coolsite.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main()