fix: corrige extração de texto de abstract em document.py - #1034
fix: corrige extração de texto de abstract em document.py#1034Rossi-Luciano wants to merge 4 commits into
Conversation
O texto de abstract/trans-abstract parava de ser extraído em XMLArticle.get_abstracts() porque o dict retornado por XMLAbstracts.get_abstracts() do packtools (>=4.15.0) deixou de conter a chave "text" (regressão introduzida em scieloorg/packtools#1064, que substituiu essa linha por graphic_href/fig_id/caption sem intenção). Isso zerava o abstract de qualquer artigo processado desde então, em qualquer coleção. Alguns XMLs migrados legados (ex.: coleção URY) também têm o texto do resumo solto, fora de <p>/<sec>, fora do padrão SPS - o que faz o texto ficar vazio mesmo com a chave "text" presente. get_abstracts() agora tenta, em ordem, a chave "text" do packtools, a recomposição a partir de p/sections e a extração bruta do XML ignorando o <title>, para cobrir os dois casos. Também isola exceções por nó, para que um abstract malformado não descarte os demais do mesmo artigo. Refs: scieloorg#1031, scieloorg/packtools#1064 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cobre XMLArticle.get_abstracts(): resumo simples com <p>, resumo estruturado com <sec>, resumo sem <p> (estrutura do XML real da issue), artigo sem abstract, e isolamento de falha - um abstract/trans-abstract malformado não pode descartar os resumos dos demais nós do mesmo artigo. Refs: scieloorg#1031 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
| import logging | ||
|
|
||
| from packtools.sps.models.v2.abstract import XMLAbstracts | ||
| from packtools.sps.validation.models.abstract import Abstract |
There was a problem hiding this comment.
@Rossi-Luciano não misturar modelo para obter os dados com os modelos de validação. Eles tem funções diferentes. No modelo de validação teria que evidenciar, por exemplo, ausência de resumo se tivesse que existir resumo. No caso de modelo para obter os dados, mesmo que um resumo não existisse não precisaria retornar o abstract de um determinado idioma com None, por exemplo.
| _STANDARD_ABSTRACTS_XPATH = ( | ||
| ".//abstract[not(@abstract-type)] | .//trans-abstract[not(@abstract-type)]" | ||
| ) |
There was a problem hiding this comment.
@Rossi-Luciano isso deveria estar no packtools e ficar transparente no upload ao usar um modelo do packtools
| yield {"language": lang, "text": text} | ||
| except Exception as e: | ||
| return [] | ||
| nodes = self.xmltree.xpath(self._STANDARD_ABSTRACTS_XPATH) |
There was a problem hiding this comment.
@Rossi-Luciano este código todo deveria ser no packtools. O modelo para obter os dados deve considerar que o xml não está perfeito. Mas cuidado para que os xmls que estiverem de acordo com o esperado retornem os dados corretamente. Corrija o modelo from packtools.sps.models.v2.abstract import XMLAbstracts acrescentando o caso indicado no issue e cuidando para que os demais casos sigam funcionando
Abstract.text (e, por consequência, Abstract.data["text"]) só lia title/p de <sec> ou <p> soltos, e retornava vazio quando o resumo legado tinha texto solto diretamente sob <abstract>/<trans-abstract>, fora de <p>/<sec>. Isso ocorre em alguns XMLs migrados (ex.: coleção URY) convertidos por versões do scielo_migration anteriores à correção em scieloorg/scielo_migration@2905ea5. Adiciona fallback: quando não há <sec> nem <p> com conteúdo, extrai o texto bruto do nó via itertext(), removendo o texto do <title> quando presente. Comportamento existente é preservado (title sozinho, sem texto solto, continua retornando ""). Refs: scieloorg/scms-upload#1031, scieloorg/scms-upload#1034
document.py voltava a extrair texto de abstract manualmente (packtools.sps.validation.models.abstract.Abstract + XPath e fallback próprios) porque o packtools 4.16.8 não expunha a chave "text" e nunca lia resumos sem wrapper <p>/<sec> (caso legado da coleção URY). Os dois problemas foram corrigidos no packtools: - chave "text" restaurada em scieloorg/packtools#1261 (4.16.9) - texto sem <p>/<sec> extraído em scieloorg/packtools#1272 (4.16.11) Com o pin subindo para 4.16.11, get_abstracts() volta a usar XMLAbstracts(self.xmltree).get_abstracts() diretamente, transparente, como antes deste bug — sem duplicar lógica de extração que pertence ao packtools, conforme apontado no review de scieloorg#1034. Refs: scieloorg#1031, scieloorg/packtools#1261, scieloorg/packtools#1272
|
PR não resolve, mas ao usar o packtools 4.16.11, problema é resolvido |
O que esse PR faz?
Corrige a extração do texto de
abstract/trans-abstractemXMLArticle.get_abstracts()(publication/utils/document.py), que estava zerando o resumo de artigos publicados em duas situações independentes:4.15.0(presente também na4.16.4de produção), o dict retornado porAbstract.datado packtools deixou de conter a chave"text"— foi substituída, sem intenção, porgraphic_href/fig_id/captionno PR scieloorg/packtools#1064. Isso afeta qualquer artigo, de qualquer coleção, processado com packtools ≥ 4.15.0 desde fev/2026.<p>/<sec>, por terem sido convertidos por uma versão doscielo_migrationanterior à correção feita em2905ea5(09/01/2026). O packtools nunca leu texto fora de<p>/<sec>— nem antes nem depois da regressão do item 1 — então esse caso persiste independentemente do fix no packtools.get_abstracts()agora tenta, em cascata: (a) a chavetextnativa do packtools, (b) recomposição a partir dep/sections(mesma lógica que a propertytextdo packtools já fazia antes da regressão — cobre o item 1 caso o packtools ainda não tenha sido corrigido), (c) extração bruta do XML ignorando o<title>(cobre o item 2). Também isola exceções por nó, para que umabstract/trans-abstractmalformado não descarte os resumos dos demais nós do mesmo artigo.Onde a revisão poderia começar?
publication/utils/document.py, classeXMLArticle, métodoget_abstracts()(e os dois métodos auxiliares logo abaixo,_compose_abstract_text_from_iteme_extract_raw_abstract_text).Como este poderia ser testado manualmente?
<p>ou<sec><p>) e verificar que oabstract/abstractsdo payload de publicação continua preenchido.<p>) e verificar que o resumo passa a ser extraído.python -m unittest publication.utils.test_document— os 4 novos testes de regressão cobrem: resumo simples com<p>, resumo estruturado com<sec>, resumo sem<p>(estrutura real da issue), e isolamento de falha (um nó malformado não zera os demais).Validei manualmente os três cenários acima contra as duas versões de packtools relevantes — a pinada em
requirements/base.txt(4.16.8) e a de produção (4.16.4, instalada a partir do tag correspondente) — e contra o XML real anexado à issue: os 9 testes do módulo passam nas duas versões, e a extração funciona ponta a ponta nos dois idiomas do artigo de exemplo.Algum cenário de contexto que queira dar?
Este fix não depende de nenhuma das duas correções de raiz relacionadas, e continua funcionando corretamente mesmo depois delas serem feitas:
text) for aberto e for para produção, o item (a) da cascata passa a funcionar de novo e os itens (b)/(c) seguem como fallback, sem conflito.scielo_migration(commit2905ea5, já em produção da ferramenta desde jan/2026) evita que novas conversões produzam o padrão malformado do item 2, mas não corrige retroativamente os XMLs já convertidos/migrados antes dessa data — por isso o item (c) da cascata continua necessário para tolerar esse legado na publicação, independentemente de uma eventual remigração desses artigos específicos.Também identifiquei, mas não mexi neste PR: existe um parâmetro
abstractemArticlePayload.add_main_metadata()(publication/api/document.py) que nunca é atribuído aself.data["abstract"]— código morto/vestigial, coerente comXMLArticle.get_main_metadata()sempre retornarabstract=None. Não afeta este bug, mas é um ponto de limpeza para um PR separado.Screenshots
Não aplicável (correção de lógica de processamento, sem interface).
Quais são os tickets relevantes?
Referências
scielo_migrationpara novas conversões (item 2)Segurança da informação (NSI.04)
Este PR manipula dados sensíveis ou pessoais (LGPD)?
Este PR altera autenticação, autorização, controle de acesso ou gerenciamento de sessão?
Este PR introduz, atualiza ou remove dependências de terceiros?
packtools.sps.models.v2.abstract.XMLAbstracts→packtools.sps.validation.models.abstract.Abstract, mesma dependência, sem alteração de versão)Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?
Este PR concatena, monta ou executa comandos SQL, HTML ou JavaScript a partir de entrada externa?
Este PR expõe novos endpoints, telas ou serviços?
Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?