Skip to content
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The application allows you to automate the process of generating a bibliography

Supported citation styles:
- ГОСТ Р 7.0.5-2008
- American Psychological Association (APA7)

## Installation

Expand Down
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

Поддерживаемые стили цитирования:
- ГОСТ Р 7.0.5-2008
- American Psychological Association (APA7)

Установка
=========
Expand Down
50 changes: 50 additions & 0 deletions src/formatters/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,53 @@ class ArticlesCollectionModel(BaseModel):
publishing_house: str
year: int = Field(..., gt=0)
pages: str


class JournalArticleModel(BaseModel):

"""
Модель статьи из журнала:

.. code-block::

JournalArticleModel(
authors="Иванов И.М., Петров С.Н.",
article_title="Наука как искусство",
journal_title="Образование и наука",
year=2020,
journal_issue=10,
pages="25-30",
)
"""

authors: str
article_title: str
journal_title: str
year: int = Field(..., gt=0)
journal_issue: int = Field(..., gt=0)
pages: str


class NewspaperArticleModel(BaseModel):

"""
Модель статьи из газеты:

.. code-block::

NewspaperArticleModel(
authors="Иванов И.М., Петров С.Н.",
article_title="Наука как искусство",
newspaper_title="Южный Урал",
year=1980,
date="01.10",
article_number=5,
)
"""

authors: str
article_title: str
newspaper_title: str
year: int = Field(..., gt=0)
date: str
article_number: int = Field(..., gt=0)
105 changes: 105 additions & 0 deletions src/formatters/styles/apa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""
Стиль цитирования по APA.
"""
from string import Template

from pydantic import BaseModel

from formatters.models import BookModel, InternetResourceModel
from formatters.styles.base import BaseCitationStyle
from logger import get_logger


logger = get_logger(__name__)


class APABook(BaseCitationStyle):
"""
Форматирование для книг.
"""

data: BookModel

@property
def template(self) -> Template:
return Template("$authors ($year). $title$edition. $publishing_house")

def substitute(self) -> str:

logger.info('Форматирование книги "%s" ...', self.data.title)

return self.template.substitute(
authors=self.data.authors,
title=self.data.title,
edition=self.get_edition(),
city=self.data.city,
publishing_house=self.data.publishing_house,
year=self.data.year,
pages=self.data.pages,
)

def get_edition(self) -> str:
"""
Получение отформатированной информации об издательстве.

:return: Информация об издательстве.
"""

return f" ({self.data.edition} изд.)" if self.data.edition else ""


class APAInternetResource(BaseCitationStyle):
"""
Форматирование для интернет-ресурсов.
"""

data: InternetResourceModel

@property
def template(self) -> Template:
return Template("$website ($access_date) $article $link")

def substitute(self) -> str:

logger.info('Форматирование интернет-ресурса "%s" ...', self.data.article)

return self.template.substitute(
article=self.data.article,
website=self.data.website,
link=self.data.link,
access_date=self.data.access_date,
)


class APACitationFormatter:
"""
Базовый класс для итогового форматирования списка источников.
"""

formatters_map = {
BookModel.__name__: APABook,
InternetResourceModel.__name__: APAInternetResource,
}

def __init__(self, models: list[BaseModel]) -> None:
"""
Конструктор.

:param models: Список объектов для форматирования
"""

formatted_items = []
for model in models:
if type(model).__name__ in self.formatters_map:
formatted_items.append(self.formatters_map.get(type(model).__name__)(model)) # type: ignore

self.formatted_items = formatted_items

def format(self) -> list[BaseCitationStyle]:
"""
Форматирование списка источников.

:return:
"""

return sorted(self.formatted_items, key=lambda item: item.formatted)
71 changes: 69 additions & 2 deletions src/formatters/styles/gost.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@

from pydantic import BaseModel

from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel
from formatters.models import (
BookModel,
InternetResourceModel,
ArticlesCollectionModel,
JournalArticleModel,
NewspaperArticleModel,
)
from formatters.styles.base import BaseCitationStyle
from logger import get_logger

Expand Down Expand Up @@ -103,6 +109,64 @@ def substitute(self) -> str:
)


class GOSTJournalArticle(BaseCitationStyle):
"""
Форматирование для статьи из журнала.
"""

data: JournalArticleModel

@property
def template(self) -> Template:
return Template(
"$authors $article_title // $journal_title. $year. № $journal_issue. С. $pages."
)

def substitute(self) -> str:

logger.info(
'Форматирование статьи из журнала "%s" ...', self.data.article_title
)

return self.template.substitute(
authors=self.data.authors,
article_title=self.data.article_title,
journal_title=self.data.journal_title,
year=self.data.year,
journal_issue=self.data.journal_issue,
pages=self.data.pages,
)


class GOSTNewspaperArticle(BaseCitationStyle):
"""
Форматирование для статьи из газеты.
"""

data: NewspaperArticleModel

@property
def template(self) -> Template:
return Template(
"$authors $article_title // $newspaper_title. $year. № $article_number. $date."
)

def substitute(self) -> str:

logger.info(
'Форматирование статьи из журнала "%s" ...', self.data.article_title
)

return self.template.substitute(
authors=self.data.authors,
article_title=self.data.article_title,
newspaper_title=self.data.newspaper_title,
year=self.data.year,
date=self.data.date,
article_number=self.data.article_number,
)


class GOSTCitationFormatter:
"""
Базовый класс для итогового форматирования списка источников.
Expand All @@ -112,6 +176,8 @@ class GOSTCitationFormatter:
BookModel.__name__: GOSTBook,
InternetResourceModel.__name__: GOSTInternetResource,
ArticlesCollectionModel.__name__: GOSTCollectionArticle,
JournalArticleModel.__name__: GOSTJournalArticle,
NewspaperArticleModel.__name__: GOSTNewspaperArticle,
}

def __init__(self, models: list[BaseModel]) -> None:
Expand All @@ -123,7 +189,8 @@ def __init__(self, models: list[BaseModel]) -> None:

formatted_items = []
for model in models:
formatted_items.append(self.formatters_map.get(type(model).__name__)(model)) # type: ignore
if type(model).__name__ in self.formatters_map:
formatted_items.append(self.formatters_map.get(type(model).__name__)(model)) # type: ignore

self.formatted_items = formatted_items

Expand Down
23 changes: 16 additions & 7 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import click

from formatters.styles.apa import APACitationFormatter
from formatters.styles.gost import GOSTCitationFormatter
from logger import get_logger
from readers.reader import SourcesReader
Expand All @@ -21,7 +22,6 @@ class CitationEnum(Enum):
"""

GOST = "gost" # ГОСТ Р 7.0.5-2008
MLA = "mla" # Modern Language Association
APA = "apa" # American Psychological Association


Expand Down Expand Up @@ -77,14 +77,23 @@ def process_input(
)

models = SourcesReader(path_input).read()
formatted_models = tuple(
str(item) for item in GOSTCitationFormatter(models).format()
)

logger.info("Генерация выходного файла ...")
Renderer(formatted_models).render(path_output)
formatter_styles = {
CitationEnum.GOST.name: GOSTCitationFormatter,
CitationEnum.APA.name: APACitationFormatter,
}

if citation in formatter_styles:
formatted_models = tuple(
str(item) for item in formatter_styles[citation](models).format() # type: ignore
)

logger.info("Генерация выходного файла ...")
Renderer(formatted_models).render(path_output)

logger.info("Команда успешно завершена.")
logger.info("Команда успешно завершена.")
else:
logger.error("Неизвестный стиль форматирования")


if __name__ == "__main__":
Expand Down
Loading