From 96f25434289989c4c015a4655f608dad1cb29bdf Mon Sep 17 00:00:00 2001 From: Rossi-Luciano Date: Mon, 6 Jul 2026 10:24:19 -0300 Subject: [PATCH 1/2] =?UTF-8?q?fix(pubmed):=20trata=20aus=C3=AAncia=20de?= =?UTF-8?q?=20PubDate=20como=20erro=20em=20vez=20de=20gerar=20Journal=20in?= =?UTF-8?q?v=C3=A1lido?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Journal/PubDate é obrigatório na DTD do PubMed ((..., PubDate), sem "?"), mas xml_pubmed_pub_date_pipe só preenche a tag quando encontra uma data reconhecida. pipeline_pubmed agora levanta MissingRequiredPubDateError quando isso não acontece, e o CLI (pubmed_generator) informa o erro ao usuário e não escreve saída, em vez de gerar um Journal inválido segundo a DTD. Co-Authored-By: Claude Sonnet 5 --- packtools/sps/formats/pubmed.py | 11 +++++++ packtools/sps/formats/pubmed_generator.py | 8 ++++- tests/sps/formats/test_pubmed.py | 39 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/packtools/sps/formats/pubmed.py b/packtools/sps/formats/pubmed.py index f99b2651d..8adc55c7c 100644 --- a/packtools/sps/formats/pubmed.py +++ b/packtools/sps/formats/pubmed.py @@ -16,6 +16,12 @@ ) +class MissingRequiredPubDateError(Exception): + """Raised when a SciELO article has no usable publication date, so the + DTD-required PubMed.dtd `Journal/PubDate` element (`(..., PubDate)`, + no `?`) cannot be filled in.""" + + def xml_pubmed_article_pipe(): return ET.Element("Article") @@ -265,6 +271,11 @@ def pipeline_pubmed(xml_tree, pretty_print=True): xml_pubmed_volume_pipe(xml_pubmed, xml_tree) xml_pubmed_issue_pipe(xml_pubmed, xml_tree) xml_pubmed_pub_date_pipe(xml_pubmed, xml_tree) + if xml_pubmed.find("Journal/PubDate") is None: + raise MissingRequiredPubDateError( + "Journal/PubDate é obrigatório na DTD do PubMed e não foi " + "possível determinar uma data de publicação para este artigo." + ) xml_pubmed_article_title_pipe(xml_pubmed, xml_tree) xml_pubmed_first_page_pipe(xml_pubmed, xml_tree) xml_pubmed_elocation_pipe(xml_pubmed, xml_tree) diff --git a/packtools/sps/formats/pubmed_generator.py b/packtools/sps/formats/pubmed_generator.py index eccd7388c..feae77566 100644 --- a/packtools/sps/formats/pubmed_generator.py +++ b/packtools/sps/formats/pubmed_generator.py @@ -1,4 +1,5 @@ import argparse +import sys from packtools.sps.formats import pubmed from packtools.sps.utils import xml_utils @@ -27,7 +28,12 @@ def main(): arguments = parser.parse_args() xml_tree = xml_utils.get_xml_tree(arguments.path_to_read) - xml_pubmed = pubmed.pipeline_pubmed(xml_tree) + try: + xml_pubmed = pubmed.pipeline_pubmed(xml_tree) + except pubmed.MissingRequiredPubDateError as exc: + print(f"Erro: {exc}", file=sys.stderr) + raise SystemExit(1) + with open(arguments.path_to_write, "w", encoding="utf-8") as file: file.write(xml_pubmed) print(f"Arquivo criado em: {arguments.path_to_write}") diff --git a/tests/sps/formats/test_pubmed.py b/tests/sps/formats/test_pubmed.py index a8afad598..85cebab60 100644 --- a/tests/sps/formats/test_pubmed.py +++ b/tests/sps/formats/test_pubmed.py @@ -25,6 +25,8 @@ xml_pubmed_citations, xml_pubmed_abstract, xml_pubmed_other_abstract, + pipeline_pubmed, + MissingRequiredPubDateError, ) @@ -1828,6 +1830,43 @@ def test_xml_pubmed_other_abstract(self): self.assertEqual(obtained, expected) +class PipelinePubmedRequiredPubDate(unittest.TestCase): + def test_pipeline_pubmed_raises_when_no_pub_date_is_found(self): + xml_tree = ET.fromstring( + '
' + '' + '' + '' + '' + '
' + ) + + with self.assertRaises(MissingRequiredPubDateError): + pipeline_pubmed(xml_tree) + + def test_pipeline_pubmed_does_not_raise_when_pub_date_is_found(self): + xml_tree = ET.fromstring( + '
' + '' + '' + '' + '06' + '01' + '2023' + '' + '' + '' + '
' + ) + + xml_pubmed = pipeline_pubmed(xml_tree) + + self.assertIn(" Date: Fri, 10 Jul 2026 13:30:51 -0300 Subject: [PATCH 2/2] refactor(pubmed): move required-PubDate check into a generic pipe-level error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Endereça o comentário de review da @robertatakenaka na #1250: o check de obrigatoriedade deve morar na função que constrói o elemento (xml_pubmed_pub_date_pipe), não solto em pipeline_pubmed depois do fato -- e a ausência do elemento é um problema do dado de entrada, não da geração de saída. MissingRequiredPubDateError vira MissingRequiredElementError(element_path), já pronta para ser reusada pelos outros elementos obrigatórios de Journal (PublisherName, JournalTitle, Issn) numa issue de acompanhamento. --- packtools/sps/formats/pubmed.py | 49 ++++++++++++----------- packtools/sps/formats/pubmed_generator.py | 2 +- tests/sps/formats/test_pubmed.py | 16 ++------ 3 files changed, 31 insertions(+), 36 deletions(-) diff --git a/packtools/sps/formats/pubmed.py b/packtools/sps/formats/pubmed.py index 8adc55c7c..92f78dba8 100644 --- a/packtools/sps/formats/pubmed.py +++ b/packtools/sps/formats/pubmed.py @@ -16,10 +16,17 @@ ) -class MissingRequiredPubDateError(Exception): - """Raised when a SciELO article has no usable publication date, so the - DTD-required PubMed.dtd `Journal/PubDate` element (`(..., PubDate)`, - no `?`) cannot be filled in.""" +class MissingRequiredElementError(Exception): + """Raised when a SciELO article has no data for an element the PubMed + DTD marks as required (no `?`), so a valid
cannot be built + for it. `element_path` identifies which element (e.g. "Journal/PubDate").""" + + def __init__(self, element_path): + self.element_path = element_path + super().__init__( + f"{element_path} é obrigatório na DTD do PubMed e não foi " + "possível determinar seu valor para este artigo." + ) def xml_pubmed_article_pipe(): @@ -133,20 +140,21 @@ def xml_pubmed_pub_date_pipe(xml_pubmed, xml_tree): """ date = get_date(xml_tree) - if date is not None: - dt = ET.Element("PubDate") - dt.set("PubStatus", "epublish") - for element in ["year", "month", "day"]: - # TODO - # Season - # The season of publication. e.g.,Winter, Spring, Summer, Fall. Do not use if a Month is available. - # There is no example of using this value in the files. - - if date.get(element): - el = ET.Element(element.capitalize()) - el.text = date.get(element) - dt.append(el) - xml_pubmed.find("Journal").append(dt) + if date is None: + raise MissingRequiredElementError("Journal/PubDate") + dt = ET.Element("PubDate") + dt.set("PubStatus", "epublish") + for element in ["year", "month", "day"]: + # TODO + # Season + # The season of publication. e.g.,Winter, Spring, Summer, Fall. Do not use if a Month is available. + # There is no example of using this value in the files. + + if date.get(element): + el = ET.Element(element.capitalize()) + el.text = date.get(element) + dt.append(el) + xml_pubmed.find("Journal").append(dt) def xml_pubmed_replaces_pipe(xml_pubmed, xml_tree): @@ -271,11 +279,6 @@ def pipeline_pubmed(xml_tree, pretty_print=True): xml_pubmed_volume_pipe(xml_pubmed, xml_tree) xml_pubmed_issue_pipe(xml_pubmed, xml_tree) xml_pubmed_pub_date_pipe(xml_pubmed, xml_tree) - if xml_pubmed.find("Journal/PubDate") is None: - raise MissingRequiredPubDateError( - "Journal/PubDate é obrigatório na DTD do PubMed e não foi " - "possível determinar uma data de publicação para este artigo." - ) xml_pubmed_article_title_pipe(xml_pubmed, xml_tree) xml_pubmed_first_page_pipe(xml_pubmed, xml_tree) xml_pubmed_elocation_pipe(xml_pubmed, xml_tree) diff --git a/packtools/sps/formats/pubmed_generator.py b/packtools/sps/formats/pubmed_generator.py index feae77566..e77bb9caa 100644 --- a/packtools/sps/formats/pubmed_generator.py +++ b/packtools/sps/formats/pubmed_generator.py @@ -30,7 +30,7 @@ def main(): xml_tree = xml_utils.get_xml_tree(arguments.path_to_read) try: xml_pubmed = pubmed.pipeline_pubmed(xml_tree) - except pubmed.MissingRequiredPubDateError as exc: + except pubmed.MissingRequiredElementError as exc: print(f"Erro: {exc}", file=sys.stderr) raise SystemExit(1) diff --git a/tests/sps/formats/test_pubmed.py b/tests/sps/formats/test_pubmed.py index 85cebab60..5284a39b9 100644 --- a/tests/sps/formats/test_pubmed.py +++ b/tests/sps/formats/test_pubmed.py @@ -26,7 +26,7 @@ xml_pubmed_abstract, xml_pubmed_other_abstract, pipeline_pubmed, - MissingRequiredPubDateError, + MissingRequiredElementError, ) @@ -508,11 +508,6 @@ def test_xml_pubmed_pub_date_pipe_without_year(self): self.assertEqual(obtained, expected) def test_xml_pubmed_pub_date_pipe_without_date(self): - expected = ( - '
' - '' - '
' - ) xml_pubmed = ET.fromstring( '
' '' @@ -529,11 +524,8 @@ def test_xml_pubmed_pub_date_pipe_without_date(self): '
' ) - xml_pubmed_pub_date_pipe(xml_pubmed, xml_tree) - - obtained = ET.tostring(xml_pubmed, encoding="utf-8").decode("utf-8") - - self.assertEqual(obtained, expected) + with self.assertRaises(MissingRequiredElementError): + xml_pubmed_pub_date_pipe(xml_pubmed, xml_tree) def test_xml_pubmed_article_title_pipe(self): expected = ( @@ -1843,7 +1835,7 @@ def test_pipeline_pubmed_raises_when_no_pub_date_is_found(self): '
' ) - with self.assertRaises(MissingRequiredPubDateError): + with self.assertRaises(MissingRequiredElementError): pipeline_pubmed(xml_tree) def test_pipeline_pubmed_does_not_raise_when_pub_date_is_found(self):