Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Solution #25

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,39 @@ CodeKiller777
Ручной ввод пути к файлу (через консоль, через правку переменной в коде и т.д.) недопустим. Необходимость любых ручных действий с файлами в процессе работы программы будут обнулять решение.

## Автор решения
Фролов Иван Владимирович

## Описание реализации
В рамках решения поставленной задачи была реализована основная процедура:
1. top_contributors

Несколько вспомогательных:
1. validate_data
2. validate_line
3. read_commits_file
4. form_res_file

А также класс, содержащий все необходимые скрипту константы:
1. Constants

Работает всё это так:
Вызывается процедура top_contributors, где из списка всех неуникальных встречающихся в файле commits.txt имен пользователей формируется список с заданным количеством главных участников, а затем из полученного списка формируется строка, которая записывается в результирующий файл.

Список всех неуникальных встречающихся в файле commits.txt имен пользователей формирует процедура read_commits_file. Она построчно считывает файл, и если строка соответствует всем указанным в ТЗ требованиям к данным, то записывает имя пользователя в список. В противном случае строка игнорируется. Для проверки всех требований к данным используются процедуры validate_data и validate_line. За исключением даты, для проверки данных были использованы регулярные выражения, записанные в классе Constants. Для даты же была написана специальная процедура, так как необходимо проверить не только формат даты, но и её корректность.

Запись в результирующий файл осуществляет процедура form_res_file. Она записывает в файл строку, сформированную из списка главных участников.


## Инструкция по сборке и запуску решения
Если у вас не установлен python, то его необходимо скачать [тут](https://www.python.org/downloads/). И в установщике проставить все галочки.

*Все нижеописанные команды необзодмо выполнять в cmd. А сам необходимо производить из дериктории, в которой лежит 'commits.txt'

Если файл commits.txt находится в той же папке, что и main.py:
```
pytnon main.py
```
Если же файл main.py расположен в другой директории:
```
python {путь к main.py}
```
137 changes: 137 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from dataclasses import dataclass
from collections import Counter
from datetime import datetime
import re


@dataclass(frozen=True)
class Constants:
"""
Класс констант, который содержит необходимые константы для скрипта.

Attributes:
res_file (str): Дефолтное имя результурющего файла.
username_pattern (str): Паттерн регулярных выражений для проверки имен пользователей.
commit_hash_pattern (str): Паттерн регулярных выражений для проверки хэшей коммита.
date_pattern (str): Шаблон формата даты для парсинга дат.
top_users (int): Количество ведущих участников, которые будут включены в список.
"""

res_file = 'result.txt'
username_pattern = r'^[a-zA-Z][a-zA-Z0-9_]*$'
commit_hash_pattern = r'^[a-f0-9]{7}$'
date_pattern = '%Y-%m-%dT%H:%M:%S'
top_users = 3


def validate_data(date_str: str) -> bool:
"""
Проверка, имеет ли данная строка даты правильный формат и корректную дату.

Args:
date_str (str): Строка, содержащая дату, подлежащая проверке.

Returns:
bool: True, если строка даты является допустимой, иначе False.
"""
try:
date = datetime.strptime(date_str, Constants.date_pattern)

if date > datetime.now():
return False

except ValueError:
return False

else:
return True


def validate_line(line: list) -> bool:
"""
Проверка на соответствие строки данных ожидаемому формату.

Args:
line (list): Список элементов из строки входных данных.

Returns:
bool: True, если список является допустимым, иначе False..
"""
if len(line) != 3:
return False

if not re.match(Constants.username_pattern, line[0]):
return False

if not re.match(Constants.commit_hash_pattern, line[1]):
return False

if not validate_data(line[2]):
return False

return True


def form_res_file(t_contributors: list) -> None:
"""
Записывает имена пользователей лучших участников в файл с названием "result.txt".

Args:
t_contributors (list): Список кортежей, содержащих лучших участников и количество их коммитов.
"""

try:
with open(Constants.res_file, 'w') as file:
file.write('\n'.join([pair[0] for pair in t_contributors]))

except Exception as e:
print(f"<form_res_file> Error writing to file: {e}")


def read_commits_file(input_file: str) -> list:
"""
Читает данные о коммитах из файла и возвращает список уникальных пользователей.

Args:
input_file (str): Путь к входному файлу, содержащему данные о коммитах.

Returns:
list: Список уникальных пользователей, упомянутых в файле коммитов.
"""

try:
users = []

with open(input_file, 'r') as file:
for line in file:
elements = line.rstrip('\n').split()

if not validate_line(elements):
continue

users.append(elements[0])

return users

except FileNotFoundError:
print(f"<top3_contributors> Input file '{input_file}' not found.")
return []

except Exception as e:
print(f"<top3_contributors> An error occurred: {e}")
return []


def top_contributors(input_file: str) -> None:
"""
Находит лучших участников из входного файла и записываеи результаты в 'result.txt'.

Args:
input_file (str): Путь к входному файлу, содержащему данные о коммитах.
"""
t_contributors = Counter(read_commits_file(input_file)).most_common(Constants.top_users)

form_res_file(t_contributors)


top_contributors('commits.txt')