anthropics / anthropics/skills

pdf skill: extract_form_field_info.py corrupts/crashes on comboboxes whose /Opt entries are bare strings

Abierto Apto para principiantes
#1,469 0 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
Python
Estrellas
176k
Forks
20.9k
Merge medio
7 h 21 min
PR fusionados (30 d)
5

Descripción

## Summary

`skills/pdf/scripts/extract_form_field_info.py` assumes every choice-field option (`/Opt`) is a `[export_value, display_text]` pair. Per ISO 32000-1 §12.7.4.4, an `/Opt` array entry may instead be a **single text string** (used as both the export value and the display text). On such fields the script silently produces corrupted output, and crashes outright when any option is a single character.

## Buggy code (`skills/pdf/scripts/extract_form_field_info.py`, lines 35-41)

```python
elif ft == "/Ch":
field_dict["type"] = "choice"
states = field.get("/_States_", [])
field_dict["choice_options"] = [{
"value": state[0],
"text": state[1],
} for state in states]
```

`states` comes from pypdf's `/_States_`, which for `/Ch` fields is the raw `/Opt` array verbatim (`pypdf/_doc_common.py`: `retval[key]["/_States_"] = obj["/Opt"]`). When `/Opt` holds bare strings, `state[0]`/`state[1]` index into the string instead of a pair.

## Reproduction

Create a combobox whose `/Opt` is bare strings, then run the script (pypdf 6.13.1):

```python
from pypdf import PdfWriter
from pypdf.generic import (DictionaryObject, ArrayObject, NameObject,
TextStringObject, NumberObject)
w = PdfWriter(); page = w.add_blank_page(width=300, height=300)
f = DictionaryObject()
f[NameObject("/FT")] = NameObject("/Ch")
f[NameObject("/T")] = TextStringObject("colors")
f[NameObject("/Ff")] = NumberObject(1 << 17) # Combo
f[NameObject("/Opt")] = ArrayObject([TextStringObject(s) for s in ("Red","Green","Blue")])
f[NameObject("/Subtype")] = NameObject("/Widget")
f[NameObject("/Rect")] = ArrayObject([NumberObject(x) for x in (50,50,250,80)])
f[NameObject("/P")] = page.indirect_reference
ref = w._add_object(f); page[NameObject("/Annots")] = ArrayObject([ref])
acro = DictionaryObject(); acro[NameObject("/Fields")] = ArrayObject([ref])
w._root_object[NameObject("/AcroForm")] = w._add_object(acro)
w.write(open("bare_opt.pdf","wb"))
```

```
$ python extract_form_field_info.py bare_opt.pdf out.json
```

**Result — silent corruption:**

```json
"choice_options": [
{"value": "R", "text": "e"},
{"value": "G", "text": "r"},
{"value": "B", "text": "l"}
]
```

`"Red"` becomes `value="R", text="e"` (chars 0 and 1 of the string).

**Result with a single-character option (e.g. `/Opt = ["A","B"]`) — hard crash:**

```
File "extract_form_field_info.py", line 40, in make_field_dict
"text": state[1],
IndexError: string index out of range
```

## Impact

Any real-world PDF using string-form `/Opt` (common for simple dropdowns) either gets its choice values/labels garbled one character at a time — with no error — or crashes the whole extraction on a single-letter option. Because the output feeds downstream form-filling, the corruption is silent and misleading.

## Suggested fix

Normalize each entry, treating a bare string as its own value and text:

```python
field_dict["choice_options"] = [
{"value": s, "text": s} if isinstance(s, str) else {"value": s[0], "text": s[1]}
for s in states
]
```

Environment: pypdf 6.13.1, Python 3.13; upstream file fetched from `anthropics/skills@main`.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Línea de trabajo

Start in skills/pdf/scripts/extract_form_field_info.py at the choice-field handling around lines 35-41, then run the supplied bare_opt.pdf reproduction with pypdf 6.13.1. Done means bare-string options retain the same value and text, paired options remain supported, and single-character options no longer crash.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
tooling
Tipo de issue
Error
Dificultad
2/5
Tiempo estimado
1-3 horas
Estado de actividad
Tranquilo
Claridad
Bien especificado
Aptitud para principiantes
88/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.