feat(pubmed): envolver saída em ArticleSet/DOCTYPE e corrigir ordem dos elementos#1243
Conversation
…os elementos pipeline_pubmed() gerava um <Article> solto, sem o envelope <ArticleSet> e DOCTYPE exigidos pela DTD do PubMed. Extrai a construção do <Article> para build_pubmed_article() e adiciona pipeline_pubmed_set() para agrupar múltiplos artigos num único <ArticleSet> (pré-requisito da scieloorg#1241). Validação contra a DTD oficial (lxml.etree.DTD + https://dtd.nlm.nih.gov/ncbi/pubmed/in/PubMed.dtd) expôs 2 bugs no pipeline, corrigidos aqui: Abstract/OtherAbstract precisavam vir antes de CopyrightInformation/CoiStatement/ObjectList/ReferenceList, e VernacularTitle nunca era chamado apesar de implementado e testado. Refs scieloorg#1226, scieloorg#1234
Reconcilia scieloorg#1242 com o envelope ArticleSet desta branch. Journal/PubDate é obrigatório na DTD do PubMed; build_pubmed_article agora levanta MissingRequiredPubDateError quando não encontra data, em vez de gerar um Journal inválido. pipeline_pubmed_set continua estrito (propaga o erro para qualquer artigo inválido do lote). Extrai build_article_set_xml (wrap de <Article>s já construídos em <ArticleSet> + DOCTYPE) de dentro de pipeline_pubmed_set, para uso por chamadores que precisem filtrar artigos inválidos antes de montar o documento final (caso do CLI em lote da scieloorg#1241). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…el error Per review on scieloorg#1250: the required-element check belongs to the pipe function that builds the element, not bolted on after the fact in build_pubmed_article -- and a missing element reflects incomplete source data, not a transform bug. MissingRequiredPubDateError becomes MissingRequiredElementError(element_path), raised directly inside xml_pubmed_pub_date_pipe, ready to be reused for the other DTD-required Journal children (PublisherName, JournalTitle, Issn) in a follow-up.
…perdida Encontrados ao validar as 26 amostras reais de tests/samples/ contra a DTD real do PubMed em vez de só 1-2 arquivos escolhidos a dedo. 1. get_date() só olhava article_date (epub), ignorando collection_date (pub-type="epub-ppub"/date-type="collection") -- o padrão mais comum em artigos SciELO mais antigos. Isso descartava 21 de 26 (81%) das amostras reais do lote inteiro por "falta de PubDate", quando na verdade tinham data. references.py e oai_dc.py já fazem esse fallback manualmente; só pubmed.py não fazia. 2. xml_pubmed_citations quebrava com AttributeError quando <ref-list> não tem <title> (opcional no JATS), pois presumia que xml_pubmed_title_reference_list já tinha criado <ReferenceList>. Agora cria o elemento se necessário -- válido pela DTD (ReferenceList (Title?, Reference*, ReferenceList*)). 3. get_first_page só olhava elocation-id, nunca fpage; LastPage não existia. Artigos com paginação tradicional (fpage/lpage) perdiam essa informação por completo. Agora FirstPage prefere fpage e cai para elocation-id só quando não há paginação (fluxo de Publicação Contínua); LastPage foi implementado. Validado: 24/26 amostras reais passam na DTD real (as 2 restantes dependem do fix de Author FirstName/LastName de scieloorg#1236/scieloorg#1245, ainda não mesclado nesta branch -- não são regressão destes fixes).
|
Adicionado mais um commit a este PR (
Validado: 24/26 amostras reais passam na DTD real agora (as 2 restantes dependem do fix de Suíte: 57/57 passando. |
…ra a DTD Diferente de test_pubmed.py (uma pipe por vez, XML sintético mínimo), este teste roda o pipeline completo (build_pubmed_article + build_article_set_xml) em cada amostra real de tests/samples/*.xml e valida o resultado contra a DTD real do PubMed. A DTD foi vendorizada em tests/fixtures/pubmed/PubMed.dtd para o teste não depender de rede (CI sem acesso à internet, ou instabilidade do servidor da NLM não devem quebrar a suíte). Essa é exatamente a lacuna que deixou passar despercebidos os 3 bugs corrigidos no commit anterior (PubDate/collection_date, crash em citations, FirstPage/LastPage) por 8 PRs já abertos. Duas amostras (example.xml, 0034-8910-rsp-48-2-0249.xml) ainda dependem de fixes que vivem em scieloorg#1236/PR scieloorg#1245 (Author FirstName/ LastName pairing e fallback `or []` em get_affiliations), ainda não mesclados nesta branch -- marcadas em KNOWN_FAILURES com asserção inversa, para que a suíte avise (ao invés de silenciosamente continuar verde) quando alguém puder remover a entrada.
|
Adicionado mais um commit ( Até agora A suíte nova:
Testado: confirmei que a suíte realmente pega regressão (reverti o fix de |
O que esse PR faz?
Adiciona o envelope
<!DOCTYPE ArticleSet ...>+<ArticleSet>exigido pela DTD do PubMed à saída depacktools/sps/formats/pubmed.py, que hoje gera um<Article>solto e inválido segundo a DTD oficial.<Article>(antes inline empipeline_pubmed) parabuild_pubmed_article(xml_tree).pipeline_pubmed_set(xml_trees, pretty_print=True), que agrupa N artigos num único<ArticleSet>— pré-requisito para o processamento em lote da CLI (Pubmed XML: CLI em lote (.zip) e registro como comando instalável #1241).pipeline_pubmed(xml_tree, pretty_print=True)com a assinatura original (delega parapipeline_pubmed_set([xml_tree], ...)), então nenhum código que já chama essa função quebra.Ao validar a saída contra a DTD oficial real do PubMed (não o validador web citado na issue-mãe, que é para outro formato — ver seção de contexto), apareceram 2 bugs no pipeline existente, corrigidos neste PR:
Abstract/OtherAbstractprecisavam vir antes deCopyrightInformation/CoiStatement/ObjectList/ReferenceListno<Article>— a DTD exige essa ordem (Abstract?, OtherAbstract*, CopyrightInformation?, CoiStatement?, ObjectList?, ReferenceList*), e o pipeline gerava na ordem inversa.xml_pubmed_vernacular_title_pipenunca era chamado dentro do pipeline, apesar de implementado e coberto por teste próprio (test_xml_pubmed_vernacular_title_pipe) — código morto por falta de wiring.Onde a revisão poderia começar?
packtools/sps/formats/pubmed.py, a partir da constantePUBMED_DOCTYPEaté o fim do arquivo:xml_pubmed_article_set_pipe,build_pubmed_article,pipeline_pubmed_set,pipeline_pubmed. Nenhuma função de pipe individual (xml_pubmed_X_pipe) foi alterada — só a orquestração e ordem em volta delas.Como este poderia ser testado manualmente?
source .venv/bin/activate && python -m pytest tests/sps/formats/test_pubmed.py -v(48 passed: 46 originais + 2 novos cobrindo o envelope).DOCTYPE+<ArticleSet><Article>...</Article></ArticleSet>, não um<Article>solto.VALID: True, tanto para artigo único quanto parapipeline_pubmed_setcom 2 artigos no mesmoArticleSet.Algum cenário de contexto que queira dar?
A #1226 pede um conversor completo SPS 1.10 → PubMed XML. O módulo já existia (
pubmed.py/pubmed_generator.py, 46 testes) mas não do zero — o trabalho foi quebrado em 8 sub-issues (#1234–#1241), sendo esta a primeira (#1234), pré-requisito estrutural para o processamento em lote (#1241).O link do validador referenciado na #1226 (
ncbi.nlm.nih.gov/projects/linkout/doc/file-validator.html) é para XML de LinkOut (outro sistema NCBI, de outro formato) — colar a saída deste pipeline lá retorna "Unknown file content", que não é sinal de erro no XML gerado. A validação real precisa ser feita contra a DTD do PubMed ArticleSet (https://dtd.nlm.nih.gov/ncbi/pubmed/in/PubMed.dtd, a mesma referenciada noDOCTYPEque este PR adiciona), vialxml.etree.DTDouxmllint --dtdvalid. Foi assim que os 2 bugs de ordenação/wiring corrigidos aqui foram encontrados.Um terceiro achado da validação (
Journal/PubDateobrigatório na DTD, mas ausente quando o artigo fonte não tem data reconhecida) ficou fora do escopo deste PR e virou a #1242.Screenshots
Não se aplica — mudança em geração de XML, sem interface gráfica.
Quais são tickets relevantes?
Closes #1234. Relacionado a #1226 (issue-mãe), #1241 (depende deste PR), #1242 (achado durante a validação, escopo separado).
Referências