Skip to content

Corrige erro de Unicode surrogate em migração de PDFs#818

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/fix-pdf-names-processing-error
Draft

Corrige erro de Unicode surrogate em migração de PDFs#818
Copilot wants to merge 4 commits intomainfrom
copilot/fix-pdf-names-processing-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 3, 2026

O que esse PR faz?

Corrige DataError: Unicode low surrogate must follow a high surrogate que interrompe completamente a migração de fascículos quando PDFs têm caracteres especiais nos nomes (ex: "Sumário.pdf").

Python lê esses nomes com surrogates de escape (\udce1). PostgreSQL rejeita surrogates ao salvar JSON. Solução: sanitiza surrogates antes de persistir no banco.

Arquivos modificados:

  • core/utils/string_utils.py - Nova função sanitize_unicode_surrogates() que limpa surrogates recursivamente em estruturas aninhadas
  • proc/models.py - Operation.finish() agora sanitiza detail antes de salvar
  • core/utils/test_string_utils.py - Testes cobrindo casos reais de falha
# Antes: PostgreSQL rejeita
detail = {"failures": [{"file": "Sum\udce1rio.pdf"}]}
self.detail = detail  # ❌ DataError

# Depois: Surrogates substituídos por U+FFFD
detail = sanitize_unicode_surrogates(detail)
self.detail = detail  # ✅ {"failures": [{"file": "Sum?rio.pdf"}]}

Onde a revisão poderia começar?

  1. core/utils/string_utils.py - Lógica de sanitização
  2. proc/models.py linha 31, 172-174 - Aplicação da sanitização
  3. core/utils/test_string_utils.py - Casos de teste

Como este poderia ser testado manualmente?

  1. Execute migração de fascículo com PDFs de nomes especiais no site clássico (ex: coleção PSI, vinculo v9n2)
  2. Verifique que a tarefa task_migrate_and_publish_articles_by_issue completa sem interrupção
  3. Confirme no TaskTracker que status não fica "interrupted"
  4. Logs mostrarão nomes com '?' no lugar de caracteres especiais

Alternativamente: python /tmp/test_sanitize.py para testes unitários.

Algum cenário de contexto que queira dar?

Criticidade: 🔴 Bloqueia migração de múltiplos fascículos da coleção PSI

Root cause: Site clássico contém PDFs com nomes fora da norma (ls -lah mostra 'Sum'$'\341''rio.pdf'). Python 3 usa surrogateescape ao ler filesystem, gerando strings com surrogates inválidos.

Trade-off: Nomes nos logs aparecem como "Sum?rio.pdf" em vez de "Sumário.pdf", mas mantém rastreabilidade e permite migração continuar.

Recomendação futura: Padronizar nomes de arquivos no site clássico.

Screenshots

N/A - Correção backend sem interface visual

Quais são tickets relevantes?

Issue #[número será linkado automaticamente pelo sistema]

Referências

Original prompt

This section details on the original issue you should resolve

<issue_title>Interrupção no processamento de fascículo devido à nomes de PDFs: django.db.utils.DataError: Unicode low surrogate must follow a high surrogate</issue_title>
<issue_description>### Descrição do problema
Ao executar a tarefa migrate_and_publish_articles para revistas da coleção PSI, alguns fascículos não foram processados porque a subtarefa proc.tasks.task_migrate_and_publish_articles_by_issue foi interrompida, registrando o seguinte erro:

{'stats': {'total_processed': 0, 'total_to_process': 0, 'total_migrated_records': 0}, 'events': ["STATUS=['REPROC', 'TODO', 'DONE', 'PENDING', 'BLOCKED']", 'docs_status: DONE', 'Migrate document records', 'Migrate issue files'], 'params': {'item': 'vinculo v9n2 (psi)', 'status': ['REPROC', 'TODO', 'DONE', 'PENDING', 'BLOCKED'], 'user_id': 2, 'username': None, 'article_pids': [], 'force_update': True, 'issue_proc_id': 4576, 'force_migrate_document_files': True, 'force_migrate_document_records': True}, 'traceback': '[\' File "/app/proc/tasks.py", line 1041, in task_migrate_and_publish_articles_by_issue\\n total_migrated_files = issue_proc.get_files_from_classic_website(\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\', \' File "/app/proc/models.py", line 1262, in get_files_from_classic_website\\n operation.finish(\\n\', \' File "/app/proc/models.py", line 177, in finish\\n self.save()\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 902, in save\\n self.save_base(\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 1005, in save_base\\n parent_inserted = self._save_parents(\\n ^^^^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 1058, in _save_parents\\n updated = self._save_table(\\n ^^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 1138, in _save_table\\n updated = self._do_update(\\n ^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 1203, in _do_update\\n return filtered._update(values) > 0\\n ^^^^^^^^^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 1286, in _update\\n return query.get_compiler(self.db).execute_sql(ROW_COUNT)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 2060, in execute_sql\\n row_count = super().execute_sql(result_type)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1623, in execute_sql\\n cursor.execute(sql, params)\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 79, in execute\\n return self._execute_with_wrappers(\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers\\n return executor(sql, params, many, context)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 100, in _execute\\n with self.db.wrap_database_errors:\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__\\n raise dj_exc_value.with_traceback(traceback) from exc_value\\n\', \' File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 105, in _execute\\n return self.cursor.execute(sql, params)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\']', 'exceptions': [], 'exception_type': "<class 'django.db.utils.DataError'>", 'exception_message': 'invalid input syntax for type json\nLINE 1: ...classic_website\', "completed" = false, "detail" = \'{"failure...\n ^\nDETAIL: Unicode low surrogate must follow a high surrogate.\nCONTEXT: JSON data, line 1: ...cielo_www/pepsic/bases/pdf/vinculo/v9n2/Sum\\udce1...\n'} 

Listando os arquivos no diretório bases/pdf do site clássico, há arquivos com nomes fora da norma, com caracteres especiais.

Passos para reproduzir o problema

  1. Execute a tarefa migrate_and_publish_articles para um fascículo de um periódico que tenha um PDF dentro do diretório de PDFs do site clássico com o nome contendo caracteres especiais. Ex: "Sumário.pdf"
  2. Acesse a lista TaskTracker e filtre os registros com status "Interrupted"
  3. Observe que o registro da tarefa proc.tasks.task_migrate_and_publish_articles_by_issue para o fascículo aparece na lista
  4. Acesse o registro e observe o erro descrito acima

Comportamento esperado

O erro não deveria ocorrer, a migração do fascículo inteiro não deveria ser interrompida.

Screenshots ou vídeos

Lista Task Tracker com os registros de tarefas interrompidas:

<img width="2956" height="888" alt="Image" src="https://github.com/user-attachments/assets/45db4479-0fcf-4f06-a751-530a8ae...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits February 3, 2026 20:57
…ish()

Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix interruption in article processing due to PDF names Corrige erro de Unicode surrogate em migração de PDFs Feb 3, 2026
Copilot AI requested a review from robertatakenaka February 3, 2026 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interrupção no processamento de fascículo devido à nomes de PDFs: django.db.utils.DataError: Unicode low surrogate must follow a high surrogate

2 participants