Skip to content

Commit

Permalink
[polish] Code style fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
co-andrey-l committed Apr 30, 2024
1 parent 0fe6d7b commit 406d8b2
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 38 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.9"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -17,7 +17,8 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install python-telegram-bot==12.8
pip install pylint
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
pylint $(git ls-files '*.py')
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vscode
autom4te.cache
.github
.env
.env
.DS_Store
6 changes: 0 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
FROM python:3.9

# Установка зависимостей
RUN pip install python-telegram-bot==12.8

# Копирование исходного кода в контейнер
COPY . /app

# Копирование файла .env в контейнер
COPY .env /app/.env

# Установка рабочей директории
WORKDIR /app

# Команда для запуска приложения с использованием переменных окружения из .env
CMD ["sh", "-c", "export $(xargs < .env) && python main.py"]
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
# Телеграм-бот для анализа PINFL
# Telegram Bot for PINFL Analysis

Этот проект представляет собой телеграм-бота, который анализирует введенный пользователем ПИНФЛ (Персональный идентификационный номер физического лица) и сообщает о его валидности, а также о дате рождения, коде региона и других параметрах.
[![linting: pylint](https://img.shields.io/badge/linting-pylint-yellowgreen)](https://github.com/pylint-dev/pylint)

## Зачем этот проект нужен?
This project is a Telegram bot that analyzes the PINFL (Personal Identification Number for Individual Taxpayer) entered by the user and reports its validity, as well as its birth date, region code, and other parameters.

ПИНФЛ (PINFL) - это уникальный идентификационный номер, используемый в ряде стран для идентификации граждан. Этот проект предназначен для обработки и анализа PINFL, чтобы убедиться в его корректности и предоставить информацию о дате рождения и других данных, содержащихся в этом номере.
## Why is this project needed?

## Как использовать?
PINFL (PINFL) is a unique identification number used in several countries to identify citizens. This project is intended for processing and analyzing PINFL to ensure its correctness and provide information about the birth date and other data contained in this number.

1. Перейдите в деррикторию проекта
## How to use?

2. Скопируйте ``` .env.example ``` в ``` .env ```
1. Navigate to the project directory.

3. Обновите все значения в ``` .env ```
2. Copy ``` .env.example ``` to ``` .env ```.

3. Update all values in ``` .env ```.

4. ``` docker build -t pinfl_bot . ```

5. ``` docker run -d pinfl_bot ```

## Дополнительные функции
## Additional features

1. Бот предварительно проверяет введенный текст на наличие только цифр и длину не менее 14 символов. Если введенный текст не соответствует этим критериям, бот отправит сообщение с соответствующим предупреждением.
1. The bot pre-checks the entered text for the presence of only digits and a length of at least 14 characters. If the entered text does not meet these criteria, the bot will send a message with the corresponding warning.

2. Если введенный PINFL короче 14 символов, недостающие символы будут заполнены нулями перед анализом.
2. If the entered PINFL is shorter than 14 characters, the missing characters will be filled with zeros before analysis.
32 changes: 23 additions & 9 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
""""Module providing receiving requests from users in a telegram bot."""

import datetime
import os
import random
Expand All @@ -6,14 +8,16 @@
from pinfl_utilities_parser import PinflUtilitiesParser


def start(update, context):
def start(update, context): # pylint: disable=unused-argument
"""Handling the start function."""
update.message.reply_text(
"Привет! Отправь мне PINFL для анализа и я скажу валидный он или нет.\n"
"Тут все честно, я не сохраняю никаких данных о тебе или о том, что ты пишешь."
)


def echo(update, context):
def echo(update, context): # pylint: disable=unused-argument
"""Handling the pinfl check function."""
pinfl_text = update.message.text.strip()

if pinfl_text.isdigit() and len(pinfl_text) >= 14:
Expand All @@ -27,40 +31,50 @@ def echo(update, context):
response += "- Неправильная дата.\n"
if not parser.validate_check_digit():
correct_check_digit = parser.calculate_check_digit()
response += f"- Неправильная контрольная цифра. Правильная контрольная цифра: {correct_check_digit}\n"
response += (
"- Неправильная контрольная цифра. "
f"Правильная контрольная цифра: {correct_check_digit}\n"
)
if not parser.validate_area_code():
response += "- Неправильный код региона.\n"
if not parser.validate_citizen_serial_number():
response += "- Неправильный серийный номер гражданина.\n"
else:
response = "Неверный PINFL. Проверьте, что он содержит только цифры и имеет длину не менее 14 символов."
response = (
"Неверный PINFL. Проверьте, что он содержит только "
"цифры и имеет длину не менее 14 символов."
)

update.message.reply_text(response)


def generate_pinfl(update, context):
def generate_pinfl(update, context): # pylint: disable=unused-argument
"""Handling the generate function."""
generator = PinflUtilitiesGenerator()
gender = random.choice(["male", "female"])
birth_date = datetime.date(
random.randint(1900, 2005), random.randint(1, 12), random.randint(1, 28)
)
pinfl = generator.generate_pinfl(gender, birth_date)
formatted_birth_date = birth_date.strftime("%d %B\(%m\) %Y")
pinfl = generator.generate(gender, birth_date)
formatted_birth_date = birth_date.strftime("%d %B\\(%m\\) %Y")
update.message.reply_text(
f"```{pinfl}```\nДата рожденья: {formatted_birth_date}\nГендер: \#{gender}",
f"```{pinfl}```\nДата рожденья: {formatted_birth_date}\nГендер: \\#{gender}",
parse_mode="MarkdownV2",
)


def main():
"""Point of entry."""

token = os.environ.get("TELEGRAM_BOT_TOKEN")
updater = Updater(token, use_context=True)
dp = updater.dispatcher

dp.add_handler(CommandHandler("start", start))
dp.add_handler(CommandHandler("generate_pinfl", generate_pinfl))
dp.add_handler(MessageHandler(Filters.text & ~Filters.command, echo))

print(f"bot launched successfully")
print("Bot launched successfully")

updater.start_polling()

Expand Down
32 changes: 23 additions & 9 deletions pinfl_utilities_generator.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
"""Random PINFL generation module."""

import random
import datetime


class PinflUtilitiesGenerator:
def generate_pinfl(self, gender, birth_date):
century = str(self.gender_date_index(gender, birth_date))
"""Random PINFL generation."""

def generate(self, gender, birth_date):
"""PINFL generation function."""

century = str(self._gender_date_index(gender, birth_date))

month = str(birth_date.month).zfill(2)
day = str(birth_date.day).zfill(2)
decade = str(birth_date.year % 100)

area_code = str(random.randint(1, 999)).zfill(3)
serial_number = str(random.randint(1, 999)).zfill(3)
pinfl_digits = [

digits = [
str(digit)
for digit in century + day + month + decade + area_code + serial_number
]
check_digit = self._calculate_check_digit(pinfl_digits)
return "".join(pinfl_digits) + str(check_digit)

def gender_date_index(self, gender, birth_date):
check_digit = self._calculate_check_digit(digits)
return "".join(digits) + str(check_digit)

def generate_pinfl(self, gender, birth_date):
"""Generate PINFL."""

return self.generate(gender, birth_date)

def _gender_date_index(self, gender, birth_date):
gender_shift_number = 1 if gender == "female" else 0
return (birth_date.year // 100) - 17 + gender_shift_number

def _calculate_check_digit(self, pinfl_digits):
def _calculate_check_digit(self, digits):
weight_func = [7, 3, 1, 7, 3, 1, 7, 3, 1, 7, 3, 1, 7]
sum_digits = sum(
int(digit) * weight for digit, weight in zip(pinfl_digits, weight_func)
int(digit) * weight for digit, weight in zip(digits, weight_func)
)
return sum_digits % 10
23 changes: 23 additions & 0 deletions pinfl_utilities_parser.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
"""Utilities for parsing PINFL (Personal Identification Number for Individual Taxpayer)"""

from collections import namedtuple
from datetime import date


class PinflUtilitiesParser:
"""Class for parsing PINFL"""

WEIGHT_FUNC = [7, 3, 1, 7, 3, 1, 7, 3, 1, 7, 3, 1, 7]
BEGINNING_CENTURY = 17

Expand All @@ -23,54 +27,67 @@ class PinflUtilitiesParser:
)

def __init__(self, value):
"""Initialize PinflUtilitiesParser with PINFL value."""
self.value = "".join(filter(str.isdigit, str(value)))

@property
def century_and_gender(self):
"""Extract century and gender from the PINFL."""
return int(self.value[0])

@property
def gender(self):
"""Determine gender based on PINFL."""
return "male" if self.century_and_gender % 2 == 1 else "female"

@property
def century(self):
"""Calculate century from PINFL."""
return (((self.century_and_gender + 1) // 2) + self.BEGINNING_CENTURY) * 100

@property
def decade(self):
"""Extract decade from PINFL."""
return int(self.value[5:7])

@property
def year(self):
"""Calculate year from PINFL."""
return self.century + self.decade

@property
def month(self):
"""Extract month from PINFL."""
return int(self.value[3:5])

@property
def day(self):
"""Extract day from PINFL."""
return int(self.value[1:3])

@property
def birth_date(self):
"""Calculate birth date from PINFL."""
return date(self.year, self.month, self.day) if self.is_valid_date() else None

@property
def area_code(self):
"""Extract area code from PINFL."""
return self.value[7:10]

@property
def citizen_serial_number(self):
"""Extract citizen serial number from PINFL."""
return self.value[10:13]

@property
def check_digit(self):
"""Extract check digit from PINFL."""
return int(self.value[13])

@property
def parts(self):
"""Get the parts of the PINFL."""
return self.Parts(
area_code=self.area_code,
check_digit=self.check_digit,
Expand All @@ -85,6 +102,7 @@ def parts(self):
)

def is_valid(self):
"""Check if the PINFL is valid."""
return len(self.value) == 14 and (
self.is_valid_date()
and self.validate_check_digit()
Expand All @@ -93,22 +111,27 @@ def is_valid(self):
)

def is_valid_date(self):
"""Check if the birth date in the PINFL is valid."""
try:
date(self.year, self.month, self.day)
return True
except ValueError:
return False

def validate_check_digit(self):
"""Validate the check digit of the PINFL."""
return self.check_digit == self.calculate_check_digit()

def validate_area_code(self):
"""Validate the area code of the PINFL."""
return int(self.area_code) != 0

def validate_citizen_serial_number(self):
"""Validate the citizen serial number of the PINFL."""
return int(self.citizen_serial_number) != 0

def calculate_check_digit(self):
"""Calculate the check digit of the PINFL."""
pinfl_numbers = list(map(int, self.value))
return (
sum(
Expand Down

0 comments on commit 406d8b2

Please sign in to comment.