From f66b5c38ad142d8bb0a4db46f5f6f858b0bdc393 Mon Sep 17 00:00:00 2001 From: NCat Date: Fri, 27 Jan 2023 01:03:03 +0500 Subject: [PATCH 1/2] =?UTF-8?q?1.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=20=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D1=81=D0=B5=D1=80=D1=82=D0=B0=D1=86=D0=B8=20=D0=B8?= =?UTF-8?q?=20=D1=81=D1=82=D0=B0=D1=82=D0=B5=D0=B9=20=D0=B8=D0=B7=20=D0=B6?= =?UTF-8?q?=D1=83=D1=80=D0=BD=D0=B0=D0=BB=D0=BE=D0=B2.=202.=20=D0=94=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BE=D1=84=D0=BE?= =?UTF-8?q?=D1=80=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=BA=D0=B0=20=D0=B8=D1=81=D1=82=D0=BE=D1=87=D0=BD=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=20=D0=BF=D0=BE=20=D1=81=D1=82=D0=B0=D0=BD?= =?UTF-8?q?=D0=B4=D0=B0=D1=80=D1=82=D1=83=20American=20Psychological=20Ass?= =?UTF-8?q?ociation.=203.=20=D0=A0=D0=B0=D0=B7=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D1=8B=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B5=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D1=85=20=D1=80=D0=B0=D0=B7=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D1=84=D1=83=D0=BD=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D0=B9.=204.=20=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=86=D0=B8=D1=8E=20(README.md=20=D0=B8=20Sphinx)?= =?UTF-8?q?=20=D0=B2=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B8=D0=B8=20=D1=81=20=D0=B2=D0=BD=D0=B5=D1=81?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D0=BC=D0=B8=20=D0=B4=D0=BE=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=D0=BC=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/source/index.rst | 1 + media/template.xlsx | Bin 30422 -> 0 bytes src/formatters/models.py | 48 ++++++++ src/formatters/styles/apa.py | 185 ++++++++++++++++++++++++++++++ src/formatters/styles/gost.py | 54 ++++++++- src/main.py | 25 ++-- src/readers/reader.py | 53 ++++++++- src/tests/conftest.py | 36 +++++- src/tests/formatters/test_apa.py | 126 ++++++++++++++++++++ src/tests/formatters/test_gost.py | 48 +++++++- src/tests/readers/test_readers.py | 54 ++++++++- 12 files changed, 614 insertions(+), 17 deletions(-) create mode 100644 src/formatters/styles/apa.py create mode 100644 src/tests/formatters/test_apa.py diff --git a/README.md b/README.md index 23fbc4c..35b1b69 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ The application allows you to automate the process of generating a bibliography Supported citation styles: - ГОСТ Р 7.0.5-2008 +- APA 7th ## Installation diff --git a/docs/source/index.rst b/docs/source/index.rst index 41d6226..b7fadf3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -7,6 +7,7 @@ Поддерживаемые стили цитирования: - ГОСТ Р 7.0.5-2008 + - APA 7th Установка ========= diff --git a/media/template.xlsx b/media/template.xlsx index 2bfee63f9c8f995ffc5d30c9772bacc7939f0ced..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 GIT binary patch literal 0 HcmV?d00001 literal 30422 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�(pTRSO3gAB_Bs-B8+ zHpoV1f={nM2!5A5AHnR)ngl6BIhy{L8tC_dyF>hq&SK_58jJA1lr|7_01J)@Q;BsI zlz*v;KFFf3^ltI^ApKvjTqkAuZ&&5~x2tCB#7myBjkSms;*P|nN!XCkN9H(uUL5{` z%KtOqK`ob0xA!3|4F9#T;P@*%Rtf$Xbh*IwyjThUwnAp%bXiswV&QKW2{Zs|ulO3dw@(eW@(l<6b`6BFzGff z7GzLoNM3rdQlp|HxrT{YsIk9#$!2{!JF?7-hi&}PdDTN{JTJk*7h4Z|`8|ox?Ur1H z!=HUG4N?(Ka9Mc}+piM`#&wM1GtG^Z4NUk448|Al9Wo6B=?g60UG#cDEE*4c0Xy^a zACgdt&{c1tA~qpM>1y=a9BX%-!ruDq;#EfHN91PChGY21TXKqX^xvO2$8V@S)xjj5 z(P zl@7UG-hL)m@vJOwewFhK48tMfibO%k3kvm&)(|&j((e^lorqhK(ZdT`ojOst!r~04 zjUAqo2CYfcN#T&c(;n-ygs3{|qv8qa$?6erTNmf?xKW-_u2orbbpq^uM=^zo2lY zF&=@H2VwjbP)6jUPpvue?-;Rw8M9O)mNKsIjB51># zIKvMN+i@EMNm74|KTSTqL|nN~l3^+N*%>xM?5(4?_#xZd{l@WnrX$r|EET#ZK3S(z z{s(Vn)M}2mJ)+ex#NZO}ldxr8GQI@oDivBk zL~va5cViB}O|r;A@gCwFv_Tx)fQ?i%>O#dz4C44lZGU}v4=*M{;xpJJNgt2WcDZfF zI6>G*icPh$TGG7Q-QGIE(4Zs53tYmLA9~r0+;}@4GY=FZW!x$jIZ(z>4N(+)q5yUk|^AOb#n6zTw%d>Onuef`|kI8zL0%Hp3?)VRcTnq(cT z2P^+PpVy{#sWOVTF{PvRtp&F%CTKBN*{3ELAEtFn1iD&)^3#{zkSyb3lhegq6dldp zMX7Ub`KDV7d0`3r=3u&@26LB|6;#8XqiEy}m;ix}c*;qISlIG2MI~umNgmm%x+#Wsk>eRI~P)S*XlPW1)%*W`wzrLbx z=ybhZom{gY&yipE^mV;Fjiz+HUvu5n?5v^EcY6K!ah!m@>2-G~7lXU9ii4YaMHp6l zRkdw!Nfx2!2lw+DkT0u`L9j2LAMwb!^z;(|`H0^s40Iah5*aXG5S=m0hx zDXfU2dq%0NRwxp;yiF){f037IN4h5L_5z_gAas^g$X=IJk*;1yKXkOmh#+v~$M}X- zb#IBqJg=uAvEIk`VDJtt-5(e=rBgUl

IP#qEqR++(u$=@uiaq9+k{52w6&HlPWV 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 S Template: + return Template( + "$authors ($year). $title. $publishing_house." + ) + + def substitute(self) -> str: + + logger.info('Форматирование книги "%s" ...', self.data.title) + + return self.template.substitute( + authors=self.data.authors, + title=self.data.title, + publishing_house=self.data.publishing_house, + year=self.data.year, + ) + + 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( + "$article (n.d.) $website $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, $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, + collection_title=self.data.collection_title, + city=self.data.city, + publishing_house=self.data.publishing_house, + year=self.data.year, + pages=self.data.pages, + ) +class APAJournalArticle(BaseCitationStyle): + """ + Форматирование для статьи из журнала. + """ + + data: JournalArticleModel + + @property + def template(self) -> Template: + return Template( + "$authors ($year). $article_title. $journal_title, $journal_number, $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_number = self.data.journal_number, + pages=self.data.pages, + ) +class APADissertation(BaseCitationStyle): + """ + Форматирование для статьи из сборника. + """ + + data: DissertationModel + + @property + def template(self) -> Template: + return Template( + "$authors ($year). $desertation_title [$canddoc диссиртация]" + ) + + def substitute(self) -> str: + + logger.info('Форматирование диссертации "%s" ...', self.data.desertation_title) + + return self.template.substitute( + authors=self.data.authors, + desertation_title=self.data.desertation_title, + canddoc=self.data.canddoc, + sience=self.data.sience, + code=self.data.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, + DissertationModel.__name__: APADissertation, + JournalArticleModel.__name__: APAJournalArticle, + } + + 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) \ No newline at end of file diff --git a/src/formatters/styles/gost.py b/src/formatters/styles/gost.py index b237f8a..6594e42 100644 --- a/src/formatters/styles/gost.py +++ b/src/formatters/styles/gost.py @@ -5,7 +5,7 @@ from pydantic import BaseModel -from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel +from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel, JournalArticleModel, DissertationModel from formatters.styles.base import BaseCitationStyle from logger import get_logger @@ -101,8 +101,58 @@ def substitute(self) -> str: year=self.data.year, pages=self.data.pages, ) +class GOSTJournalArticle(BaseCitationStyle): + """ + Форматирование для статьи из журнала. + """ + + data: JournalArticleModel + + @property + def template(self) -> Template: + return Template( + "$authors $article_title // $journal_title – $year. - №$journal_number, $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_number = self.data.journal_number, + pages=self.data.pages, + ) +class GOSTDissertation(BaseCitationStyle): + """ + Форматирование для статьи из сборника. + """ + + data: DissertationModel + + @property + def template(self) -> Template: + return Template( + "$authors, $desertation_title [Текст]: дис. ... $canddoc $sience наук: $code / $authors - $city, $year. - $pages с." + ) + + def substitute(self) -> str: + + logger.info('Форматирование диссертации "%s" ...', self.data.desertation_title) + + return self.template.substitute( + authors=self.data.authors, + desertation_title=self.data.desertation_title, + canddoc=self.data.canddoc, + sience=self.data.sience, + code=self.data.code, + city=self.data.city, + year=self.data.year, + pages=self.data.pages, + ) class GOSTCitationFormatter: """ Базовый класс для итогового форматирования списка источников. @@ -112,6 +162,8 @@ class GOSTCitationFormatter: BookModel.__name__: GOSTBook, InternetResourceModel.__name__: GOSTInternetResource, ArticlesCollectionModel.__name__: GOSTCollectionArticle, + DissertationModel.__name__: GOSTDissertation, + JournalArticleModel.__name__: GOSTJournalArticle, } def __init__(self, models: list[BaseModel]) -> None: diff --git a/src/main.py b/src/main.py index 7a9fa8e..f45866e 100644 --- a/src/main.py +++ b/src/main.py @@ -10,6 +10,7 @@ from readers.reader import SourcesReader from renderer import Renderer from settings import INPUT_FILE_PATH, OUTPUT_FILE_PATH +from formatters.styles.apa import APACitationFormatter logger = get_logger(__name__) @@ -75,16 +76,24 @@ def process_input( path_input, path_output, ) - models = SourcesReader(path_input).read() - formatted_models = tuple( - str(item) for item in GOSTCitationFormatter(models).format() - ) - - logger.info("Генерация выходного файла ...") - Renderer(formatted_models).render(path_output) + match citation: + case CitationEnum.GOST.name: + formatted_models = tuple( + str(item) for item in GOSTCitationFormatter(models).format() + ) + logger.info("Генерация выходного файла GOST ...") + Renderer(formatted_models).render(path_output) + logger.info("Команда успешно завершена.") + case CitationEnum.APA.name: + formatted_models = tuple( + str(item) for item in APACitationFormatter(models).format() + ) + Renderer(formatted_models).render(path_output) + logger.info("Генерация выходного файла APA ...") + Renderer(formatted_models).render(path_output) + logger.info("Команда успешно завершена.") - logger.info("Команда успешно завершена.") if __name__ == "__main__": diff --git a/src/readers/reader.py b/src/readers/reader.py index 9007a80..98aaab0 100644 --- a/src/readers/reader.py +++ b/src/readers/reader.py @@ -7,11 +7,12 @@ import openpyxl from openpyxl.workbook import Workbook -from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel +from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel, DissertationModel, JournalArticleModel from logger import get_logger from readers.base import BaseReader + logger = get_logger(__name__) @@ -88,6 +89,54 @@ def attributes(self) -> dict: "year": {5: int}, "pages": {6: str}, } +class DissertationReader(BaseReader): + """ + Чтение модели сборника статей. + """ + + @property + def model(self) -> Type[DissertationModel]: + return DissertationModel + + @property + def sheet(self) -> str: + return "Диссертация" + + @property + def attributes(self) -> dict: + return { + "authors": {0: str}, + "desertation_title": {1: str}, + "canddoc": {2: str}, + "sience": {3: str}, + "code": {4: str}, + "city": {5: str}, + "year": {6: int}, + "pages": {7: int}, + } +class JournalArticleReader(BaseReader): + """ + Чтение модели сборника статей. + """ + + @property + def model(self) -> Type[JournalArticleModel]: + return JournalArticleModel + + @property + def sheet(self) -> str: + return "Статья из журнала" + + @property + def attributes(self) -> dict: + return { + "authors": {0: str}, + "article_title": {1: str}, + "journal_title": {2: str}, + "year": {3: int}, + "journal_number": {4: int}, + "pages": {5: str}, + } class SourcesReader: @@ -100,6 +149,8 @@ class SourcesReader: BookReader, InternetResourceReader, ArticlesCollectionReader, + JournalArticleReader, + DissertationReader, ] def __init__(self, path: str) -> None: diff --git a/src/tests/conftest.py b/src/tests/conftest.py index ac5c9aa..00313c5 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -3,7 +3,7 @@ """ import pytest -from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel +from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel, JournalArticleModel, DissertationModel @pytest.fixture @@ -58,3 +58,37 @@ def articles_collection_model_fixture() -> ArticlesCollectionModel: year=2020, pages="25-30", ) +@pytest.fixture +def journal_articles_model_fixture() -> JournalArticleModel: + """ + Фикстура модели сборника статей. + + :return: ArticlesCollectionModel + """ + + return JournalArticleModel( + authors="Иванов И.М., Петров С.Н.", + article_title="Наука как искусство", + magazine_title = "Образование и наука", + year = 2020, + magazine_number = 10, + pages = "25-30", + ) +@pytest.fixture +def disseratation_model_fixture() -> DissertationModel: + """ + Фикстура модели сборника статей. + + :return: ArticlesCollectionModel + """ + + return DissertationModel( + authors="Иванов И.М.", + desertation_title="Наука как искусство", + canddoc="канд.", + sience="экон.", + code = "01.01.01", + city = "СПб.", + year = 2020, + pages = 199, + ) diff --git a/src/tests/formatters/test_apa.py b/src/tests/formatters/test_apa.py new file mode 100644 index 0000000..3b49e0c --- /dev/null +++ b/src/tests/formatters/test_apa.py @@ -0,0 +1,126 @@ +""" +Тестирование функций оформления списка источников по APA 7th. +""" + +from formatters.base import BaseCitationFormatter +from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel, DissertationModel, JournalArticleModel +from formatters.styles.apa import APABook, APAInternetResource, APACollectionArticle, APADissertation, APAJournalArticle + + +class TestGOST: + """ + Тестирование оформления списка источников согласно APA 7th. + """ + + def test_book(self, book_model_fixture: BookModel) -> None: + """ + Тестирование форматирования книги. + + :param BookModel book_model_fixture: Фикстура модели книги + :return: + """ + + model = APABook(book_model_fixture) + + assert ( + model.formatted + == "Иванов И.М., Петров С.Н. (2020). Наука как искусство. Просвещение." + ) + + def test_internet_resource( + self, internet_resource_model_fixture: InternetResourceModel + ) -> None: + """ + Тестирование форматирования интернет-ресурса. + + :param InternetResourceModel internet_resource_model_fixture: Фикстура модели интернет-ресурса + :return: + """ + + model = APAInternetResource(internet_resource_model_fixture) + + assert ( + model.formatted + == "Наука как искусство (n.d.) Ведомости https://www.vedomosti.ru" + ) + + def test_articles_collection( + self, articles_collection_model_fixture: ArticlesCollectionModel + ) -> None: + """ + Тестирование форматирования сборника статей. + + :param ArticlesCollectionModel articles_collection_model_fixture: Фикстура модели сборника статей + :return: + """ + + model = APACollectionArticle(articles_collection_model_fixture) + + assert ( + model.formatted + == "Иванов И.М., Петров С.Н. (2020). Наука как искусство. Сборник научных трудов, 25-30." + ) + def test_journal_articles( + self, journal_articles_model_fixture: JournalArticleModel + ) -> None: + """ + Тестирование форматирования сборника статей. + + :param JournalArticleModel journal_articles_model_fixture: Фикстура модели сборника статей + :return: + """ + + model = APAJournalArticle(journal_articles_model_fixture) + + assert ( + model.formatted + == "Иванов И.М., Петров С.Н. (2020). Наука как искусство. Образование и наука, 10, 25-30." + ) + def test_dissertation( + self, disseratation_model_fixture: DissertationModel + ) -> None: + """ + Тестирование форматирования диссертаций. + + :param DissertationModel disseratation_model_fixture: Фикстура модели диссертаций + :return: + """ + + model = APADissertation(disseratation_model_fixture) + + assert ( + model.formatted + == "Иванов И.М. (2020). Наука как искусство [канд. диссиртация]" + ) + def test_citation_formatter( + self, + book_model_fixture: BookModel, + internet_resource_model_fixture: InternetResourceModel, + articles_collection_model_fixture: ArticlesCollectionModel, + disseratation_model_fixture: DissertationModel, + journal_articles_model_fixture: JournalArticleModel + ) -> None: + """ + Тестирование функции итогового форматирования списка источников. + + :param BookModel book_model_fixture: Фикстура модели книги + :param InternetResourceModel internet_resource_model_fixture: Фикстура модели интернет-ресурса + :param ArticlesCollectionModel articles_collection_model_fixture: Фикстура модели сборника статей + :return: + """ + + models = [ + APABook(book_model_fixture), + APAInternetResource(internet_resource_model_fixture), + APACollectionArticle(articles_collection_model_fixture), + APAJournalArticle(journal_articles_model_fixture), + APADissertation(disseratation_model_fixture), + ] + result = BaseCitationFormatter(models).format() + + # тестирование сортировки списка источников + assert result[0] == models[3] + assert result[1] == models[4] + assert result[2] == models[2] + assert result[3] == models[1] + assert result[4] == models[0] diff --git a/src/tests/formatters/test_gost.py b/src/tests/formatters/test_gost.py index c93e1e7..5720beb 100644 --- a/src/tests/formatters/test_gost.py +++ b/src/tests/formatters/test_gost.py @@ -3,8 +3,8 @@ """ from formatters.base import BaseCitationFormatter -from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel -from formatters.styles.gost import GOSTBook, GOSTInternetResource, GOSTCollectionArticle +from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel, DissertationModel, JournalArticleModel +from formatters.styles.gost import GOSTBook, GOSTInternetResource, GOSTCollectionArticle, GOSTDissertation, GOSTJournalArticle class TestGOST: @@ -60,12 +60,46 @@ def test_articles_collection( model.formatted == "Иванов И.М., Петров С.Н. Наука как искусство // Сборник научных трудов. – СПб.: АСТ, 2020. – С. 25-30." ) + def test_journal_articles( + self, journal_articles_model_fixture: JournalArticleModel + ) -> None: + """ + Тестирование форматирования сборника статей. + + :param JournalArticleModel journal_articles_model_fixture: Фикстура модели сборника статей + :return: + """ + model = GOSTJournalArticle(journal_articles_model_fixture) + + assert ( + model.formatted + == "Иванов И.М., Петров С.Н. Наука как искусство // Образование и наука – 2020. - №10, 25-30." + ) + def test_dissertation( + self, disseratation_model_fixture: DissertationModel + ) -> None: + """ + Тестирование форматирования диссертаций. + + :param DissertationModel disseratation_model_fixture: Фикстура модели диссертаций + :return: + """ + + model = GOSTDissertation(disseratation_model_fixture) + + assert ( + model.formatted + == "Иванов И.М., Наука как искусство [Текст]: дис. ... канд. экон. наук: 01.01.01 / Иванов И.М. - СПб., 2020. - 199 с" + ) def test_citation_formatter( self, book_model_fixture: BookModel, internet_resource_model_fixture: InternetResourceModel, articles_collection_model_fixture: ArticlesCollectionModel, + disseratation_model_fixture: DissertationModel, + journal_articles_model_fixture: JournalArticleModel + ) -> None: """ Тестирование функции итогового форматирования списка источников. @@ -80,10 +114,14 @@ def test_citation_formatter( GOSTBook(book_model_fixture), GOSTInternetResource(internet_resource_model_fixture), GOSTCollectionArticle(articles_collection_model_fixture), + GOSTJournalArticle(journal_articles_model_fixture), + GOSTDissertation(disseratation_model_fixture), ] result = BaseCitationFormatter(models).format() # тестирование сортировки списка источников - assert result[0] == models[2] - assert result[1] == models[0] - assert result[2] == models[1] + assert result[0] == models[3] + assert result[1] == models[4] + assert result[2] == models[2] + assert result[3] == models[1] + assert result[4] == models[0] \ No newline at end of file diff --git a/src/tests/readers/test_readers.py b/src/tests/readers/test_readers.py index 67d863b..528dcd2 100644 --- a/src/tests/readers/test_readers.py +++ b/src/tests/readers/test_readers.py @@ -5,12 +5,14 @@ import pytest -from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel +from formatters.models import BookModel, InternetResourceModel, ArticlesCollectionModel, DissertationModel, JournalArticleModel from readers.reader import ( BookReader, SourcesReader, InternetResourceReader, ArticlesCollectionReader, + DissertationReader, + JournalArticleReader, ) from settings import TEMPLATE_FILE_PATH @@ -104,6 +106,56 @@ def test_articles_collection(self, workbook: Any) -> None: # проверка общего количества атрибутов assert len(model_type.schema().get("properties", {}).keys()) == 7 + def test_dissertation(self, workbook: Any) -> None: + """ + Тестирование чтения сборника статей. + + :param workbook: Объект тестовой рабочей книги. + """ + + models = DissertationReader(workbook).read() + + assert len(models) == 1 + model = models[0] + + model_type = DissertationModel + + assert isinstance(model, model_type) + assert model.authors == "Иванов И.М., Петров С.Н." + assert model.article_title == "Наука как искусство" + assert model.journal_title == "Образование и наука" + assert model.year == 2020 + assert model.city == 10 + assert model.pages == "25-30" + + # проверка общего количества атрибутов + assert len(model_type.schema().get("properties", {}).keys()) == 6 + def test_journal_article(self, workbook: Any) -> None: + """ + Тестирование чтения сборника статей. + + :param workbook: Объект тестовой рабочей книги. + """ + + models = JournalArticleReader(workbook).read() + + assert len(models) == 1 + model = models[0] + + model_type = JournalArticleModel + + assert isinstance(model, model_type) + assert model.authors == "Иванов И.М." + assert model.desertation_title == "Наука как искусство" + assert model.canddoc == "д-р. / канд." + assert model.sience == "экон." + assert model.code == "01.01.01" + assert model.city == "СПб." + assert model.year == 2020 + assert model.pages == 199 + + # проверка общего количества атрибутов + assert len(model_type.schema().get("properties", {}).keys()) == 8 def test_sources_reader(self) -> None: """ Тестирование функции чтения всех моделей из источника. From 64a91e99fc8db24cc54cbc69f58c7e6a4f226b62 Mon Sep 17 00:00:00 2001 From: NCat Date: Fri, 27 Jan 2023 22:43:13 +0500 Subject: [PATCH 2/2] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- media/template.xlsx | Bin 0 -> 30422 bytes src/formatters/models.py | 4 ++-- src/readers/reader.py | 4 ++-- src/tests/conftest.py | 8 +++---- src/tests/formatters/test_apa.py | 10 ++++----- src/tests/formatters/test_gost.py | 10 ++++----- src/tests/readers/test_readers.py | 34 ++++++++++++++++-------------- 7 files changed, 36 insertions(+), 34 deletions(-) diff --git a/media/template.xlsx b/media/template.xlsx index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2bfee63f9c8f995ffc5d30c9772bacc7939f0ced 100644 GIT binary patch literal 30422 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�(pTRSO3gAB_Bs-B8+ zHpoV1f={nM2!5A5AHnR)ngl6BIhy{L8tC_dyF>hq&SK_58jJA1lr|7_01J)@Q;BsI zlz*v;KFFf3^ltI^ApKvjTqkAuZ&&5~x2tCB#7myBjkSms;*P|nN!XCkN9H(uUL5{` z%KtOqK`ob0xA!3|4F9#T;P@*%Rtf$Xbh*IwyjThUwnAp%bXiswV&QKW2{Zs|ulO3dw@(eW@(l<6b`6BFzGff z7GzLoNM3rdQlp|HxrT{YsIk9#$!2{!JF?7-hi&}PdDTN{JTJk*7h4Z|`8|ox?Ur1H z!=HUG4N?(Ka9Mc}+piM`#&wM1GtG^Z4NUk448|Al9Wo6B=?g60UG#cDEE*4c0Xy^a zACgdt&{c1tA~qpM>1y=a9BX%-!ruDq;#EfHN91PChGY21TXKqX^xvO2$8V@S)xjj5 z(P zl@7UG-hL)m@vJOwewFhK48tMfibO%k3kvm&)(|&j((e^lorqhK(ZdT`ojOst!r~04 zjUAqo2CYfcN#T&c(;n-ygs3{|qv8qa$?6erTNmf?xKW-_u2orbbpq^uM=^zo2lY zF&=@H2VwjbP)6jUPpvue?-;Rw8M9O)mNKsIjB51># zIKvMN+i@EMNm74|KTSTqL|nN~l3^+N*%>xM?5(4?_#xZd{l@WnrX$r|EET#ZK3S(z z{s(Vn)M}2mJ)+ex#NZO}ldxr8GQI@oDivBk zL~va5cViB}O|r;A@gCwFv_Tx)fQ?i%>O#dz4C44lZGU}v4=*M{;xpJJNgt2WcDZfF zI6>G*icPh$TGG7Q-QGIE(4Zs53tYmLA9~r0+;}@4GY=FZW!x$jIZ(z>4N(+)q5yUk|^AOb#n6zTw%d>Onuef`|kI8zL0%Hp3?)VRcTnq(cT z2P^+PpVy{#sWOVTF{PvRtp&F%CTKBN*{3ELAEtFn1iD&)^3#{zkSyb3lhegq6dldp zMX7Ub`KDV7d0`3r=3u&@26LB|6;#8XqiEy}m;ix}c*;qISlIG2MI~umNgmm%x+#Wsk>eRI~P)S*XlPW1)%*W`wzrLbx z=ybhZom{gY&yipE^mV;Fjiz+HUvu5n?5v^EcY6K!ah!m@>2-G~7lXU9ii4YaMHp6l zRkdw!Nfx2!2lw+DkT0u`L9j2LAMwb!^z;(|`H0^s40Iah5*aXG5S=m0hx zDXfU2dq%0NRwxp;yiF){f037IN4h5L_5z_gAas^g$X=IJk*;1yKXkOmh#+v~$M}X- zb#IBqJg=uAvEIk`VDJtt-5(e=rBgUl

IP#qEqR++(u$=@uiaq9+k{52w6&HlPWV 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 S dict: } class DissertationReader(BaseReader): """ - Чтение модели сборника статей. + Чтение модели диссертаций. """ @property @@ -116,7 +116,7 @@ def attributes(self) -> dict: } class JournalArticleReader(BaseReader): """ - Чтение модели сборника статей. + Чтение модели статей из журнала. """ @property diff --git a/src/tests/conftest.py b/src/tests/conftest.py index 00313c5..39c7bf3 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -63,15 +63,15 @@ def journal_articles_model_fixture() -> JournalArticleModel: """ Фикстура модели сборника статей. - :return: ArticlesCollectionModel + :return: JournalArticlesnModel """ return JournalArticleModel( authors="Иванов И.М., Петров С.Н.", article_title="Наука как искусство", - magazine_title = "Образование и наука", + journal_title = "Образование и наука", year = 2020, - magazine_number = 10, + journal_number = 10, pages = "25-30", ) @pytest.fixture @@ -79,7 +79,7 @@ def disseratation_model_fixture() -> DissertationModel: """ Фикстура модели сборника статей. - :return: ArticlesCollectionModel + :return: DissertationModel """ return DissertationModel( diff --git a/src/tests/formatters/test_apa.py b/src/tests/formatters/test_apa.py index 3b49e0c..6c14411 100644 --- a/src/tests/formatters/test_apa.py +++ b/src/tests/formatters/test_apa.py @@ -119,8 +119,8 @@ def test_citation_formatter( result = BaseCitationFormatter(models).format() # тестирование сортировки списка источников - assert result[0] == models[3] - assert result[1] == models[4] - assert result[2] == models[2] - assert result[3] == models[1] - assert result[4] == models[0] + assert result[0] == models[4] + assert result[1] == models[3] + assert result[2] == models[0] + assert result[3] == models[2] + assert result[4] == models[1] diff --git a/src/tests/formatters/test_gost.py b/src/tests/formatters/test_gost.py index 5720beb..2b87722 100644 --- a/src/tests/formatters/test_gost.py +++ b/src/tests/formatters/test_gost.py @@ -90,7 +90,7 @@ def test_dissertation( assert ( model.formatted - == "Иванов И.М., Наука как искусство [Текст]: дис. ... канд. экон. наук: 01.01.01 / Иванов И.М. - СПб., 2020. - 199 с" + == "Иванов И.М., Наука как искусство [Текст]: дис. ... канд. экон. наук: 01.01.01 / Иванов И.М. - СПб., 2020. - 199 с." ) def test_citation_formatter( self, @@ -120,8 +120,8 @@ def test_citation_formatter( result = BaseCitationFormatter(models).format() # тестирование сортировки списка источников - assert result[0] == models[3] - assert result[1] == models[4] + assert result[0] == models[4] + assert result[1] == models[3] assert result[2] == models[2] - assert result[3] == models[1] - assert result[4] == models[0] \ No newline at end of file + assert result[3] == models[0] + assert result[4] == models[1] \ No newline at end of file diff --git a/src/tests/readers/test_readers.py b/src/tests/readers/test_readers.py index 528dcd2..1b0ca9a 100644 --- a/src/tests/readers/test_readers.py +++ b/src/tests/readers/test_readers.py @@ -119,17 +119,19 @@ def test_dissertation(self, workbook: Any) -> None: model = models[0] model_type = DissertationModel - assert isinstance(model, model_type) - assert model.authors == "Иванов И.М., Петров С.Н." - assert model.article_title == "Наука как искусство" - assert model.journal_title == "Образование и наука" + assert model.authors == "Иванов И.М." + assert model.desertation_title == "Наука как искусство" + assert model.canddoc == "д-р. / канд." + assert model.sience == "экон." + assert model.code == "01.01.01" + assert model.city == "СПб." assert model.year == 2020 - assert model.city == 10 - assert model.pages == "25-30" + assert model.pages == 199 + # проверка общего количества атрибутов - assert len(model_type.schema().get("properties", {}).keys()) == 6 + assert len(model_type.schema().get("properties", {}).keys()) == 8 def test_journal_article(self, workbook: Any) -> None: """ Тестирование чтения сборника статей. @@ -145,17 +147,15 @@ def test_journal_article(self, workbook: Any) -> None: model_type = JournalArticleModel assert isinstance(model, model_type) - assert model.authors == "Иванов И.М." - assert model.desertation_title == "Наука как искусство" - assert model.canddoc == "д-р. / канд." - assert model.sience == "экон." - assert model.code == "01.01.01" - assert model.city == "СПб." + assert model.authors == "Иванов И.М., Петров С.Н." + assert model.article_title == "Наука как искусство" + assert model.journal_title == "Образование и наука" assert model.year == 2020 - assert model.pages == 199 + assert model.journal_number == 10 + assert model.pages == "25-30" # проверка общего количества атрибутов - assert len(model_type.schema().get("properties", {}).keys()) == 8 + assert len(model_type.schema().get("properties", {}).keys()) == 6 def test_sources_reader(self) -> None: """ Тестирование функции чтения всех моделей из источника. @@ -163,12 +163,14 @@ def test_sources_reader(self) -> None: models = SourcesReader(TEMPLATE_FILE_PATH).read() # проверка общего считанного количества моделей - assert len(models) == 8 + assert len(models) == 10 # проверка наличия всех ожидаемых типов моделей среди типов считанных моделей model_types = {model.__class__.__name__ for model in models} assert model_types == { BookModel.__name__, InternetResourceModel.__name__, + DissertationModel.__name__, ArticlesCollectionModel.__name__, + JournalArticleModel.__name__ }