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
- APA

## 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
- APA

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


class RegulatoryActModel(BaseModel):
"""
Модель нормативного акта:
.. code-block::
RegulatoryActModel(
type="Трудовой кодекс",
name="Наука как искусство",
agree_date="02.01.2022",
act_num="8888-88",
publishing_source="Сайт России",
year=2022,
source=5,
article=15,
amended_from="01.01.2021",
)
"""

type: str
name: str
agree_date: str
act_num: str
publishing_source: str
year: int = Field(..., gt=0)
source: int = Field(..., gt=0)
article: int = Field(..., gt=0)
amended_from: str


class DissertationModel(BaseModel):
"""
Модель диссертации:
.. code-block::
DissertationModel(
author_name="Петров С.Н.",
title="Наука как искусство",
author_title="канд.",
special_field="ЭВМ.",
special_code="09.01.02",
city="СПб.",
year=2022,
pages=199,
)
"""

author_name: str = Field(..., min_length=1)
title: str = Field(..., min_length=1)
author_title: str = Field(..., min_length=1)
special_field: str = Field(..., min_length=1)
special_code: str = Field(..., min_length=1)
city: str = Field(..., min_length=1)
year: int = Field(..., gt=0)
pages: int = Field(..., gt=0)


197 changes: 197 additions & 0 deletions src/formatters/styles/apa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
"""
Стиль цитирования по APA 7.
"""
from string import Template

from pydantic import BaseModel

from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel, RegulatoryActModel, DissertationModel
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,
)

def get_edition(self) -> str:


if self.data.edition:
ed = int(self.data.edition.split("-")[0])
res = f"{ed}th"
if 10 <= ed % 100 <=19:
res = f"{ed}th"
elif ed % 10 == 1:
res = f"{ed}st"
elif ed % 10 == 2:
res = f"{ed}nd"
elif ed % 10 == 3:
res = f"{ed}rd"
return f" ({res} ed.)"
return ""


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

data: InternetResourceModel

@property
def template(self) -> Template:
return Template(
'$article. $website. (n.d.). $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,
)


class APACollectionArticle(BaseCitationStyle):
"""
Форматирование для статьи из сборника.
"""

data: ArticlesCollectionModel

@property
def template(self) -> Template:
return Template(
'$authors ($year). $article_title, $collection_title. (pp. $pages). $publishing_house.'
)

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,
collection_title=self.data.collection_title,
publishing_house=self.data.publishing_house,
year=self.data.year,
pages=self.data.pages,
)





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

data: RegulatoryActModel

@property
def template(self) -> Template:
return Template(
'$name, $act_num $publishing_source. § $article ($year).'
)

def substitute(self) -> str:

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

return self.template.substitute(
name=self.data.name,
publishing_source=self.data.publishing_source,
act_num=self.data.act_num,
article=self.data.article,
year=self.data.year,
)


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

data: DissertationModel

@property
def template(self) -> Template:
return Template(
"$author_name ($year) $title, дис. [$author_title $special_field $special_code] $city, $pages с."
)

def substitute(self) -> str:

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

return self.template.substitute(
author_name=self.data.author_name,
title=self.data.title,
author_title=self.data.author_title,
special_field=self.data.special_field,
special_code=self.data.special_code,
city=self.data.city,
year=self.data.year,
pages=self.data.pages,
)


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

formatters_map = {
BookModel.__name__: APABook,
InternetResourceModel.__name__: APAInternetResource,
ArticlesCollectionModel.__name__: APACollectionArticle,
RegulatoryActModel.__name__: APARegulatoryAct,
DissertationModel.__name__: APADissertation,

}

def __init__(self, models: list[BaseModel]) -> None:
"""
Конструктор.
:param models: Список объектов для форматирования
"""

formatted_items = []
for model in models:
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)
64 changes: 63 additions & 1 deletion src/formatters/styles/gost.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from pydantic import BaseModel

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

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


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

data: RegulatoryActModel

@property
def template(self) -> Template:
return Template(
'$type "$name" от $agree_date №$act_num // $publishing_source, $year. – №$source – Ст. $article с изм. и допол. в ред. от $amended_from.'
)

def substitute(self) -> str:

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

return self.template.substitute(
type=self.data.type,
name=self.data.name,
agree_date=self.data.agree_date,
act_num=self.data.act_num,
publishing_source=self.data.publishing_source,
year=self.data.year,
source=self.data.source,
article=self.data.article,
amended_from=self.data.amended_from,
)



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

data: DissertationModel

@property
def template(self) -> Template:
return Template(
"$author_name $title: дис. $author_title $special_field: $special_code $city $year. $pages c."
)

def substitute(self) -> str:

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

return self.template.substitute(
author_name=self.data.author_name,
title=self.data.title,
author_title=self.data.author_title,
special_code=self.data.special_code,
special_field=self.data.special_field,
city=self.data.city,
year=self.data.year,
pages=self.data.pages
)


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

def __init__(self, models: list[BaseModel]) -> None:
Expand Down
15 changes: 11 additions & 4 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import click

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

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


Expand Down Expand Up @@ -77,9 +78,15 @@ def process_input(
)

models = SourcesReader(path_input).read()
formatted_models = tuple(
str(item) for item in GOSTCitationFormatter(models).format()
)
formatter_mapping = {
CitationEnum.GOST.name: GOSTCitationFormatter,
CitationEnum.APA.name: APACitationFormatter
}
if citation not in formatter_mapping:
logger.error("Неподдерживаемый стиль")

formatter_class = formatter_mapping[citation]
formatted_models = tuple(str(item) for item in formatter_class(models).format())

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