Tengo un script de Python 2.6 que está amordazando en caracteres especiales, codificados en Latin-1, que estoy recuperando de una base de datos de SQL Server. Me gustaría imprimir estos caracteres, pero estoy algo limitado porque estoy usando una biblioteca que llama a la fábrica unicode
, y no sé cómo hacer que Python use un códec que no sea ascii
.Latin-1 y la fábrica de Unicode en Python
El script es una herramienta simple para devolver datos de búsqueda desde una base de datos sin tener que ejecutar el SQL directamente en un editor de SQL. Uso la biblioteca PrettyTable 0.5 para mostrar los resultados.
El núcleo del script es este código. Las tuplas que obtengo del cursor contienen datos enteros y de cadena, y no hay datos Unicode. (Que haría uso de adodbapi
en lugar de pyodbc
, lo que me Unicode, pero me da adodbapi
otros problemas.)
x = pyodbc.connect(cxnstring)
r = x.cursor()
r.execute(sql)
t = PrettyTable(columns)
for rec in r:
t.add_row(rec)
r.close()
x.close()
t.set_field_align("ID", 'r')
t.set_field_align("Name", 'l')
print t
Pero la columna de la Name
puede contener caracteres que quedan fuera del rango ASCII. A veces voy a conseguir un mensaje de error como este, en la línea 222 de prettytable.pyc
, cuando se llega a la llamada t.add_row
:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 12: ordinal not in range(128)
Ésta es la línea 222 en prettytable.py
. Utiliza unicode
, que es la fuente de mis problemas, y no solo en este script, sino en otros scripts de Python que he escrito.
for i in range(0,len(row)):
if len(unicode(row[i])) > self.widths[i]: # This is line 222
self.widths[i] = len(unicode(row[i]))
Por favor dígame qué estoy haciendo mal aquí. ¿Cómo puedo hacer que unicode
funcione sin hackear prettytable.py
o cualquiera de las otras bibliotecas que uso? ¿Hay incluso una manera de hacer esto?
EDITAR: El error no se produce en la instrucción print
, sino en la llamada t.add_row
.
EDITAR: Con la ayuda de Bastien Léonard, se me ocurrió la siguiente solución. No es una panacea, pero funciona.
x = pyodbc.connect(cxnstring)
r = x.cursor()
r.execute(sql)
t = PrettyTable(columns)
for rec in r:
urec = [s.decode('latin-1') if isinstance(s, str) else s for s in rec]
t.add_row(urec)
r.close()
x.close()
t.set_field_align("ID", 'r')
t.set_field_align("Name", 'l')
print t.get_string().encode('latin-1')
Terminé descodificando en el camino y codificando en el camino de salida. ¡Todo esto me da la esperanza de que todo el mundo conecte sus bibliotecas a Python 3.x más temprano que tarde!
He intentado poner la codificación en la parte superior de mis scripts, pero todavía no funciona. Probaré la decodificación explícita, pero espero que haya una solución más general. – eksortso
Probablemente no desee establecer la codificación: latin1. Eso cambia la codificación de la fuente del script, no sus datos. –
@Glenn: Sugerí eso porque pensé que 'print t' podría imprimir cadenas crudas Latin1. –