Escribiendo ficheros docx de Word con Python. Capítulo VI – Enums y Shares

tutoriales

En general, lo que hemos visto hasta ahora, lo podíamos hacer prácticamente todo desde el objeto [Document](https://pybonacci.org/2020/06/11/escribiendo-ficheros-docx-de-word-con-python-capitulo-ii-document/). Desde el mismo podemos acceder a otros objetos como los párrafos, tablas, secciones, run's,...

Pero, en el anterior capítulo, vimos que empezaron a salir algunos nombres raros como Cm, Pt o WD_PARAGRAPH_ALIGNMENT.

Vamos a importar la biblioteca y ver un poco de todo lo que dispone:

import docx
for name in dir(docx):
    if not name.startswith("__"):
        print(name, getattr(docx, name), end="\n"*2)

Lo anterior nos mostrará una serie de cosas.

Vemos que tenemos disponibles dos clases que no vamos a comentar y la función Document que nos crea una instancia del objeto Document (sí, se llaman igual la función y la clase), es decir, prácticamente todo lo que necesitamos lo podemos obtener con la función Document que nos devolverá el objeto instanciado. Todo lo demás que está disponible son una serie de módulos. Vamos a repasarlos por encima:

  • api: básicamente nos ofrece la función Document.
  • blkcntnr: aquí tenemos la clase BlockItemContainer que sirve para los contenedores como el cabecero, la celda de una tabla, el cuerpo del documento,... Dispone de métodos como add_paragraph o add_table.
  • compat: compatibilidad entre Python 2/3.
  • dml: utilidades para trabajar con color.
  • document: aquí es donde se define la clase Document.
  • enum: este lo vamos a ver a continuación algo más de detalle.
  • exceptions: varias excepciones.
  • image: nos proporciona objetos para trabajar con imágenes en los formatos más conocidos como tiff, jpg, bmp,...
  • opc: utilidades para trabajar con la Open Packaging Convention.
  • oxml: utilidades para trabajar con el Office Open XML.
  • package: utilidades para trabajar con la Open Packaging Convention.
  • parts: las diferentes partes que forman el documento.
  • section: la clase Section se encuentra aquí.
  • settings: la clase Settings se encuentra aquí.
  • shape: la clase InlineShape que usamos para añadir imágenes se encuentra aquí.
  • shared: aquí encontramos funcionalidades que se usan por los diferentes módulos y que vamos a ver en algo más de detalle a continuación.
  • styles: aquí se encuentran definidos los estilos y la clase Style.
  • text: aquí se encuentran definidas cosas como Paragraph, Table, Run.

Como veis, todo está pensado para que haya un único punto de entrada que nos sirve de proxy para acceder a las diferentes partes del documento definidas como distintas clases. El resto de la biblioteca es para poder leer y escribir el documento, comprimirlo o descomprimirlo y son cosas que no necesitamos tocar. Lo que más usamos (y haciendo el gráfico de cabeza...) sería algo así:

Además de lo anterior, lo cual hemos ido viendo por encima en anteriores secciones. hemos pasado por encima sobre algunas otras cosas que obtenemos de los módulos shared y enum.

Módulo shared

Lo más importante que tenemos en este módulo son formas de establecer tamaños o medidas de forma que el resto de la biblioteca lo pueda entender. Algunas de las clases más importantes contenidas aquí son:

from docx import shared

print(dir(shared))

Lo anterior mostrará:

['Cm', 'ElementProxy', 'Emu', 'Inches', 'Length', 'Mm', 'Parented',
 'Pt', 'RGBColor', 'Twips', '__builtins__', '__cached__', '__doc__',
 '__file__', '__loader__', '__name__', '__package__', '__spec__',
 'absolute_import', 'lazyproperty', 'print_function',
 'unicode_literals', 'write_only_property']

Todas las clases anteriores derivan de Length.

print(shared.Twips.__bases__)

Lo anterior mostrará:

(<class 'docx.shared.Length'>,)
shared.Cm(1) == shared.Mm(10)

Mostrará:

True
shared.Emu(360_000) == shared.Cm(1)

Mostrará:

True
emu = shared.Emu(360_000)
cm = shared.Cm(1)
mm = shared.Mm(10)
inch = shared.Inches(0.3937008) # 1 cm = 0.3937008 inches

Todo lo anterior sería 1 cm expresado de diferente forma. Si miramos internamente:

print(emu.real, cm.real, mm.real, inch.real)

Mostraría:

360000 360000 360000 360000

Dentro del modulo shared vemos que tenemos también la clase RGBColor. Esta clase nos ayuda a usar colores en nuestro documento y que luego la librería lo pueda usar internamente.

black = shared.RGBColor(0,0,0)
print(black)

Lo anterior mostrará:

RGBColor(0x00, 0x00, 0x00)

Módulo enum

Este módulo son enumeraciones de todo tipo que se usan en la librería. Normalmente, la mayoría no es necesario conocerlas en detalle pero algunas de ellas si que son interesantes que las conozcamos.

from docx import enum

Al siguiente, dml, no le deberíamos prestar mucha atención.

print(enum.dml.__doc__)

Lo anterior muestra:

Enumerations used by DrawingML objects

El siguiente, section, sí que puede resultar más interesante. La ayuda nos dice:

print(enum.section.__doc__)
Enumerations related to the main document in WordprocessingML files

Veamos las enumeraciones que hay en enum.section y sus valores:

for name in dir(enum.section):
    _enum = getattr(enum.section, name)
    if isinstance(_enum, enum.base.MetaEnumeration):
        print(name)
        contents = dir(getattr(enum.section, name))
        for content in contents:
            _value = getattr(_enum, content)
            if isinstance(_value,  enum.base.EnumValue):
                print("\t", content)

Lo anterior mostraría algo parecido a:

WD_HEADER_FOOTER
     EVEN_PAGE
     FIRST_PAGE
     PRIMARY
WD_HEADER_FOOTER_INDEX
     EVEN_PAGE
     FIRST_PAGE
     PRIMARY
WD_ORIENT
     LANDSCAPE
     PORTRAIT
WD_ORIENTATION
     LANDSCAPE
     PORTRAIT
WD_SECTION
     CONTINUOUS
     EVEN_PAGE
     NEW_COLUMN
     NEW_PAGE
     ODD_PAGE
WD_SECTION_START
     CONTINUOUS
     EVEN_PAGE
     NEW_COLUMN
     NEW_PAGE
     ODD_PAGE
XmlEnumeration

Tenemos valores para la sección donde podemos definir si la sección será en apaisado o en vertical, si el cabecero o pie de página estará en las paginas, pares, impares, en todas,...

El siguiente, shape, se usa para definir imágenes. La ayuda nos dice:

print(enum.shape.__doc__)

La ayuda nos dice:

Enumerations related to DrawingML shapes in WordprocessingML files

El siguiente, style, se usa para definir temas relacionados con el estilo. La ayuda nos dice:

print(enum.style.__doc__)

Lo anterior muestra:

Enumerations related to styles

Si miramos lo que hay:

for name in dir(enum.style):
    _enum = getattr(enum.style, name)
    if isinstance(_enum, enum.base.MetaEnumeration):
        print(name)
        contents = dir(getattr(enum.style, name))
        for content in contents:
            _value = getattr(_enum, content)
            if isinstance(_value,  enum.base.EnumValue):
                print("\t", content)

Lo anterior nos da:

WD_BUILTIN_STYLE
     BLOCK_QUOTATION
     BODY_TEXT
     BODY_TEXT_2
     BODY_TEXT_3
     BODY_TEXT_FIRST_INDENT
     BODY_TEXT_FIRST_INDENT_2
     BODY_TEXT_INDENT
     BODY_TEXT_INDENT_2
     BODY_TEXT_INDENT_3
     BOOK_TITLE
     CAPTION
     CLOSING
     COMMENT_REFERENCE
     COMMENT_TEXT
     DATE
     DEFAULT_PARAGRAPH_FONT
     EMPHASIS
     ENDNOTE_REFERENCE
     ENDNOTE_TEXT
     ENVELOPE_ADDRESS
     ENVELOPE_RETURN
     FOOTER
     FOOTNOTE_REFERENCE
     FOOTNOTE_TEXT
     HEADER
     HEADING_1
     HEADING_2
     HEADING_3
     HEADING_4
     HEADING_5
     HEADING_6
     HEADING_7
     HEADING_8
     HEADING_9
     HTML_ACRONYM
     HTML_ADDRESS
     HTML_CITE
     HTML_CODE
     HTML_DFN
     HTML_KBD
     HTML_NORMAL
     HTML_PRE
     HTML_SAMP
     HTML_TT
     HTML_VAR
     HYPERLINK
     HYPERLINK_FOLLOWED
     INDEX_1
     INDEX_2
     INDEX_3
     INDEX_4
     INDEX_5
     INDEX_6
     INDEX_7
     INDEX_8
     INDEX_9
     INDEX_HEADING
     INTENSE_EMPHASIS
     INTENSE_QUOTE
     INTENSE_REFERENCE
     LINE_NUMBER
     LIST
     LIST_2
     LIST_3
     LIST_4
     LIST_5
     LIST_BULLET
     LIST_BULLET_2
     LIST_BULLET_3
     LIST_BULLET_4
     LIST_BULLET_5
     LIST_CONTINUE
     LIST_CONTINUE_2
     LIST_CONTINUE_3
     LIST_CONTINUE_4
     LIST_CONTINUE_5
     LIST_NUMBER
     LIST_NUMBER_2
     LIST_NUMBER_3
     LIST_NUMBER_4
     LIST_NUMBER_5
     LIST_PARAGRAPH
     MACRO_TEXT
     MESSAGE_HEADER
     NAV_PANE
     NORMAL
     NORMAL_INDENT
     NORMAL_OBJECT
     NORMAL_TABLE
     NOTE_HEADING
     PAGE_NUMBER
     PLAIN_TEXT
     QUOTE
     SALUTATION
     SIGNATURE
     STRONG
     SUBTITLE
     SUBTLE_EMPHASIS
     SUBTLE_REFERENCE
     TABLE_COLORFUL_GRID
     TABLE_COLORFUL_LIST
     TABLE_COLORFUL_SHADING
     TABLE_DARK_LIST
     TABLE_LIGHT_GRID
     TABLE_LIGHT_GRID_ACCENT_1
     TABLE_LIGHT_LIST
     TABLE_LIGHT_LIST_ACCENT_1
     TABLE_LIGHT_SHADING
     TABLE_LIGHT_SHADING_ACCENT_1
     TABLE_MEDIUM_GRID_1
     TABLE_MEDIUM_GRID_2
     TABLE_MEDIUM_GRID_3
     TABLE_MEDIUM_LIST_1
     TABLE_MEDIUM_LIST_1_ACCENT_1
     TABLE_MEDIUM_LIST_2
     TABLE_MEDIUM_SHADING_1
     TABLE_MEDIUM_SHADING_1_ACCENT_1
     TABLE_MEDIUM_SHADING_2
     TABLE_MEDIUM_SHADING_2_ACCENT_1
     TABLE_OF_AUTHORITIES
     TABLE_OF_FIGURES
     TITLE
     TOAHEADING
     TOC_1
     TOC_2
     TOC_3
     TOC_4
     TOC_5
     TOC_6
     TOC_7
     TOC_8
     TOC_9
WD_STYLE
     BLOCK_QUOTATION
     BODY_TEXT
     BODY_TEXT_2
     BODY_TEXT_3
     BODY_TEXT_FIRST_INDENT
     BODY_TEXT_FIRST_INDENT_2
     BODY_TEXT_INDENT
     BODY_TEXT_INDENT_2
     BODY_TEXT_INDENT_3
     BOOK_TITLE
     CAPTION
     CLOSING
     COMMENT_REFERENCE
     COMMENT_TEXT
     DATE
     DEFAULT_PARAGRAPH_FONT
     EMPHASIS
     ENDNOTE_REFERENCE
     ENDNOTE_TEXT
     ENVELOPE_ADDRESS
     ENVELOPE_RETURN
     FOOTER
     FOOTNOTE_REFERENCE
     FOOTNOTE_TEXT
     HEADER
     HEADING_1
     HEADING_2
     HEADING_3
     HEADING_4
     HEADING_5
     HEADING_6
     HEADING_7
     HEADING_8
     HEADING_9
     HTML_ACRONYM
     HTML_ADDRESS
     HTML_CITE
     HTML_CODE
     HTML_DFN
     HTML_KBD
     HTML_NORMAL
     HTML_PRE
     HTML_SAMP
     HTML_TT
     HTML_VAR
     HYPERLINK
     HYPERLINK_FOLLOWED
     INDEX_1
     INDEX_2
     INDEX_3
     INDEX_4
     INDEX_5
     INDEX_6
     INDEX_7
     INDEX_8
     INDEX_9
     INDEX_HEADING
     INTENSE_EMPHASIS
     INTENSE_QUOTE
     INTENSE_REFERENCE
     LINE_NUMBER
     LIST
     LIST_2
     LIST_3
     LIST_4
     LIST_5
     LIST_BULLET
     LIST_BULLET_2
     LIST_BULLET_3
     LIST_BULLET_4
     LIST_BULLET_5
     LIST_CONTINUE
     LIST_CONTINUE_2
     LIST_CONTINUE_3
     LIST_CONTINUE_4
     LIST_CONTINUE_5
     LIST_NUMBER
     LIST_NUMBER_2
     LIST_NUMBER_3
     LIST_NUMBER_4
     LIST_NUMBER_5
     LIST_PARAGRAPH
     MACRO_TEXT
     MESSAGE_HEADER
     NAV_PANE
     NORMAL
     NORMAL_INDENT
     NORMAL_OBJECT
     NORMAL_TABLE
     NOTE_HEADING
     PAGE_NUMBER
     PLAIN_TEXT
     QUOTE
     SALUTATION
     SIGNATURE
     STRONG
     SUBTITLE
     SUBTLE_EMPHASIS
     SUBTLE_REFERENCE
     TABLE_COLORFUL_GRID
     TABLE_COLORFUL_LIST
     TABLE_COLORFUL_SHADING
     TABLE_DARK_LIST
     TABLE_LIGHT_GRID
     TABLE_LIGHT_GRID_ACCENT_1
     TABLE_LIGHT_LIST
     TABLE_LIGHT_LIST_ACCENT_1
     TABLE_LIGHT_SHADING
     TABLE_LIGHT_SHADING_ACCENT_1
     TABLE_MEDIUM_GRID_1
     TABLE_MEDIUM_GRID_2
     TABLE_MEDIUM_GRID_3
     TABLE_MEDIUM_LIST_1
     TABLE_MEDIUM_LIST_1_ACCENT_1
     TABLE_MEDIUM_LIST_2
     TABLE_MEDIUM_SHADING_1
     TABLE_MEDIUM_SHADING_1_ACCENT_1
     TABLE_MEDIUM_SHADING_2
     TABLE_MEDIUM_SHADING_2_ACCENT_1
     TABLE_OF_AUTHORITIES
     TABLE_OF_FIGURES
     TITLE
     TOAHEADING
     TOC_1
     TOC_2
     TOC_3
     TOC_4
     TOC_5
     TOC_6
     TOC_7
     TOC_8
     TOC_9
WD_STYLE_TYPE
     CHARACTER
     LIST
     PARAGRAPH
     TABLE
XmlEnumeration

Los nombres que vemos aquí están relacionados con los estilos que podemos ver, por ejemplo, en la UI de Microsoft Word y también podemos ver los contextos en los que se pueden aplicar los estilos, a nivel de párrafo, de carácter, de tabla,...

El siguiente, table, se usa para definir temas relacionados con las tablas. La ayuda nos dice:

print(enum.table.__doc__)
Enumerations related to tables in WordprocessingML files

Miramos lo que hay:

for name in dir(enum.table):
    _enum = getattr(enum.table, name)
    if isinstance(_enum, enum.base.MetaEnumeration):
        print(name)
        contents = dir(getattr(enum.table, name))
        for content in contents:
            _value = getattr(_enum, content)
            if isinstance(_value,  enum.base.EnumValue):
                print("\t", content)

Lo anterior mostrará:

Enumeration
WD_ALIGN_VERTICAL
     BOTH
     BOTTOM
     CENTER
     TOP
WD_CELL_VERTICAL_ALIGNMENT
     BOTH
     BOTTOM
     CENTER
     TOP
WD_ROW_HEIGHT
     AT_LEAST
     AUTO
     EXACTLY
WD_ROW_HEIGHT_RULE
     AT_LEAST
     AUTO
     EXACTLY
WD_TABLE_ALIGNMENT
     CENTER
     LEFT
     RIGHT
WD_TABLE_DIRECTION
     LTR
     RTL
XmlEnumeration

Toda una serie de cosas para poder trabajar con tablas y definir la altura de celdas, la alineación,...

El siguiente, text, se usa para definir temas relacionados con texto. La ayuda nos dice:

print(enum.text.__doc__)

La documentación dice:

Enumerations related to text in WordprocessingML files

Si inspeccionamos lo que hay:

for name in dir(enum.text):
    _enum = getattr(enum.text, name)
    if isinstance(_enum, enum.base.MetaEnumeration):
        print(name)
        contents = dir(getattr(enum.text, name))
        for content in contents:
            _value = getattr(_enum, content)
            if isinstance(_value,  enum.base.EnumValue):
                print("\t", content)

Veremos algo como:

WD_ALIGN_PARAGRAPH
     CENTER
     DISTRIBUTE
     JUSTIFY
     JUSTIFY_HI
     JUSTIFY_LOW
     JUSTIFY_MED
     LEFT
     RIGHT
     THAI_JUSTIFY
WD_COLOR
     AUTO
     BLACK
     BLUE
     BRIGHT_GREEN
     DARK_BLUE
     DARK_RED
     DARK_YELLOW
     GRAY_25
     GRAY_50
     GREEN
     PINK
     RED
     TEAL
     TURQUOISE
     VIOLET
     WHITE
     YELLOW
WD_COLOR_INDEX
     AUTO
     BLACK
     BLUE
     BRIGHT_GREEN
     DARK_BLUE
     DARK_RED
     DARK_YELLOW
     GRAY_25
     GRAY_50
     GREEN
     PINK
     RED
     TEAL
     TURQUOISE
     VIOLET
     WHITE
     YELLOW
WD_LINE_SPACING
     AT_LEAST
     DOUBLE
     EXACTLY
     MULTIPLE
     ONE_POINT_FIVE
     SINGLE
WD_PARAGRAPH_ALIGNMENT
     CENTER
     DISTRIBUTE
     JUSTIFY
     JUSTIFY_HI
     JUSTIFY_LOW
     JUSTIFY_MED
     LEFT
     RIGHT
     THAI_JUSTIFY
WD_TAB_ALIGNMENT
     BAR
     CENTER
     CLEAR
     DECIMAL
     END
     LEFT
     LIST
     NUM
     RIGHT
     START
WD_TAB_LEADER
     DASHES
     DOTS
     HEAVY
     LINES
     MIDDLE_DOT
     SPACES
WD_UNDERLINE
     DASH
     DASH_HEAVY
     DASH_LONG
     DASH_LONG_HEAVY
     DOTTED
     DOTTED_HEAVY
     DOT_DASH
     DOT_DASH_HEAVY
     DOT_DOT_DASH
     DOT_DOT_DASH_HEAVY
     DOUBLE
     NONE
     SINGLE
     THICK
     WAVY
     WAVY_DOUBLE
     WAVY_HEAVY
     WORDS
XmlEnumeration

Por último, aquí podemos ver un montón de cosas relacionadas con el texto.

Recapitulando

La biblioteca está pensada para que tenga un único punto de entrada. Si nuestro documento va a ser algo sencillo no necesitamos más que usar doc = docx.Document() y desde esa instancia podemos ir creándolo todo.

Si necesitamos meternos en harina y toquetear cosas tenemos toda una cantidad de nombres (enumeraciones) que nos deberían ayudar a hacer lo que tenemos en mente, siempre que el formato docx lo permita.