Найти - Пользователи
Полная версия: python3 + PyODBC = проблемы с кодировкой.
Начало » GUI » python3 + PyODBC = проблемы с кодировкой.
1
keizer08
Всем привет.
Есть приложение получающее данные из БД(mssql) ясное дело что SQL сервер на крутится на винде. Данное приложение отображает данные из БД в таблицы. С запуском на виндовс машинах проблем нет, но при запуске на Linux машинах в таблицах “каракули”. При запуске приложения идет проверка кодировки по умолчанию вот так
import sys
print(sys.getdefaultencoding())

и на виндовс и на линухе вывод гласит - “utf-8”. В Connection String явно указываю кодировку БД(cp1251).
Так вот вопрос, в чем разница? Почему на винде все ОК? а на линухе каракули? Подскажите… я уже задолбался… даже переписал на 3 питон весь проект что бы не мучаться с кодировками(но не тут то было). Не могу двинуться дальше из за этой проблемы.

получаестя от сервера у нас всегда приходит строка байтов в кодировке cp1251 не зависимо от платформы. Далее я так догадываюсь где то в недрах pyODBC эта строка перегоняется в Unicode строку потом при выводе на экран это дело перегоняется в utf-8. Т.е. строка байтов -> unicode(с использование кодировки cp1251) -> utf-8.

Если можно не отсылайте на статью по Юникоду и кодировкам, их прочитано великое множество.
reclosedev
Без кода сложно ответить. Я бы посмотрел, что попадает в Qt когда получили данные из базы, что у нее за тип, что в ней:
some_string = get_some_string_from_db()
print(type(some_string), repr(some_string))
print(some_string)
От этого можно уже смотреть где проблема. Может из БД уже ерунда приходит. Если нет, может шрифта в системе нет.
keizer08
reclosedev
Без кода сложно ответить. Я бы посмотрел, что попадает в Qt когда получили данные из базы, что у нее за тип, что в ней:
some_string = get_some_string_from_db()
print(type(some_string), repr(some_string))
print(some_string)
От этого можно уже смотреть где проблема. Может из БД уже ерунда приходит. Если нет, может шрифта в системе нет.

код:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
from Kernel.Exceptions.MyExceptions import *
import sys	
from Kernel.Util import Util
import pyodbc
class DBConnector(QtCore.QThread):
	
	waitSQL = QtCore.pyqtSignal(str, name = 'waitSQL')
	doneSQL = QtCore.pyqtSignal(str, name = 'doneSQL')
	
	def __init__(self, UID = '', PWD = '', SERVER = '', DTB = '', DRIVER = '', CHARSET = ''):
		QtCore.QThread.__init__(self)
		self.DRIVER   = DRIVER
		self.USERNAME = UID
		self.PASSWORD = PWD
		self.SERVER   = SERVER
		self.DATABASE = DTB
		self.CHARSET  = CHARSET
		self.CONNECT  = None
		self.CURSOR   = None
		self.REQUEST  = None
		self.RESPONSE = []
		self.WAIT	  = False
	def __del__(self):
		self.disconnect()
	def connecting(self):
		self.CONNECT = pyodbc.connect('DRIVER=%s;SERVER=%s;UID=%s;PWD=%s;DATABASE=%s;CHARSET=%s' % (self.DRIVER, self.SERVER, self.USERNAME, self.PASSWORD, self.DATABASE, self.CHARSET))
		print('Connection is getted')
		print('autocommin is %s' % self.CONNECT.autocommit)
	def getCursor(self):
		if self.CONNECT:
			self.CURSOR = self.CONNECT.cursor()
			print('cursor getted')
		else:
			raise NoConnection
	def runSQL(self, sql = ''):
		try:
			if sql:
				self.waitSQL[str].emit('<font color="red">Ожидаю ответа SQL, пожалуйста подождите</font>')
				self.getCursor()
				self.CURSOR.execute(sql)
				response = [row for row in self.CURSOR]
				if not response:
					print('SQL response is empty')
					raise EmptyResponse
				self.CURSOR.close()
				return response
		except pyodbc.DatabaseError:
			self.doneSQL[str].emit('<font color="red">Данные не получены</font>')
		else:
			self.doneSQL[str].emit('<font color="green">Данные получены</font>')
		finally:
			self.doneSQL[str].emit('<font color="yellow">requesr is done</font>')
	def disconnect(self):
		if self.CONNECT:
			self.CONNECT.close()
			print ('disconnect succesfull')
	def setUserName(self, username):
		self.USERNAME = username
	def getUserName(self):
		return self.USERNAME
	def setPassword(self, password):
		self.PASSWORD = password
	def setServer(self, server):
		self.SERVER = server
	def setDataBase(self, database):
		self.DATABASE = database
	def setDriver(self, driver):
		self.DRIVER = driver
	def getDriver(self):
		return self.DRIVER
	def setCharSet(self, charset):
		self.CHARSET = charset
	def getCharSet(self):
		return self.CHARSET
		
	def info(self):
		print('\n===== Connecttion Info =====')
		print('SERVER   = %s' % self.SERVER)
		print('USERNAME = %s' % self.USERNAME)
		print('DATABASE = %s' % self.DATABASE)
		print('PASSWORD = %s' % self.PASSWORD)
		print('DRIVER   = %s' % self.DRIVER)
		print('============================\n')
		
	def test(self, SERVER = '', DATABASE = '', USERNAME = '', PASSWORD = '', DRIVER = ''):
		self.setUserName(USERNAME)
		self.setPassword(PASSWORD)
		self.setServer(SERVER)
		self.setDataBase(DATABASE)
		self.setDriver(DRIVER)
		self.info()
		self.connecting()

По поводу шрифта у меня большие сомнения… не те каракули))) да и у меня в консоль выводится ответ от базы… в консоли тоже “каракули”. Видно что проблема с кодировкой.



вот что попадает в Qt на Linux:
<class 'str'> '\x00\Ue0eaf2f1\Uffebe420\Ueff1e820\Uede0f2fb\Ud15fffe8\U33302ed2\Uff003138\U0806532a\Ub70bbfb0\U0825864f\Ub722716c\U09694a7c\Ubf93fd2c\x00\x00\x08\Uc490a927\x00\U010ae9f0\Ubf93fb88𐀁\x00\x00\x00\x00\x00\x0f𐀁\x00'
��������������������������񥌪򻾰�������������􊤧򮧰����𐀁𐀁

вот что попадает в Qt на Windows:
<class 'str'> 'Оснастка для испытания_СТ.0381'
Оснастка для испытания_СТ.0381
после того как добавил вот этот кусок кода
some_string = get_some_string_from_db()
print(type(some_string), repr(some_string))
print(some_string)

В Базе данных это тип VARCHAR, хранятся там строки на русском языке.
reclosedev
Как будто pyodbc портит.
А если попробовать в Connection String не указывать кодировку, а декодировать вручную?
# тоже самое + 
print(some_string.decode('cp1251')
keizer08
reclosedev
Как будто pyodbc портит.
А если попробовать в Connection String не указывать кодировку, а декодировать вручную?
# тоже самое + 
print(some_string.decode('cp1251')

В Connection String'e кодировку я начал указывать уже когда столкнулся с проблемой… до этого ее там не было, результат был тем же.

в 3 питоне нет метода decode у строк… хотя я был бы рад если бы его оставили!)
reclosedev
keizer08
В Connection String'e кодировку я начал указывать уже когда столкнулся с проблемой… до этого ее там не было, результат был тем же.

в 3 питоне нет метода decode у строк… хотя я был бы рад если бы его оставили!)
Странно, значит pyodbc юникод (строку в терминах Py3) возвращает. Что-то с конфигурацией драйвера, PyQt тут ни при чем.
С pyodbc не сталкивался, но попробовал бы поиграться с CHARSET в строке подключения (UTF8 или latin1 поставить, например), или с результатами:
some_string.encode("utf-8").decode("cp1251")
Еще можно попробовать поискать https://www.google.com/search?q=pyodbc%20encoding
keizer08
reclosedev
keizer08
В Connection String'e кодировку я начал указывать уже когда столкнулся с проблемой… до этого ее там не было, результат был тем же.

в 3 питоне нет метода decode у строк… хотя я был бы рад если бы его оставили!)
Странно, значит pyodbc юникод (строку в терминах Py3) возвращает. Что-то с конфигурацией драйвера, PyQt тут ни при чем.
С pyodbc не сталкивался, но попробовал бы поиграться с CHARSET в строке подключения (UTF8 или latin1 поставить, например), или с результатами:
some_string.encode("utf-8").decode("cp1251")
Еще можно попробовать поискать https://www.google.com/search?q=pyodbc%20encoding

есть тот же самый проект написанный на python2.7 в котором используется тот же самый ODBC драйвер с теми же настройками, и там все ОК. Проблема pyODBC… он как то криво конвертит строку в юникод. Я так догадываюсь он ковертит ее с использованием UTF8 на линухе и cp1251 на винде… поэтому на винде конвертация проходит номрально(т.к. строка приходит от базы в cp1251), а на линухе криво. Вопрос в том почему pyODBC конвертит на винде с помощью cp1251 хотя по умолчанию стоит UTF8.
reclosedev
keizer08
Вопрос в том почему pyODBC конвертит на винде с помощью cp1251 хотя по умолчанию стоит UTF8.
Та может он из локали берет?
In [7]: import sys
 
In [8]: sys.getdefaultencoding()
Out[8]: 'ascii'
 
In [9]: import locale
 
In [10]: locale.getpreferredencoding()
Out[10]: 'cp1251'
На Линухе же, локаль обычно UTF-8.
keizer08
reclosedev
keizer08
Вопрос в том почему pyODBC конвертит на винде с помощью cp1251 хотя по умолчанию стоит UTF8.
Та может он из локали берет?
In [7]: import sys
 
In [8]: sys.getdefaultencoding()
Out[8]: 'ascii'
 
In [9]: import locale
 
In [10]: locale.getpreferredencoding()
Out[10]: 'cp1251'
На Линухе же, локаль обычно UTF-8.

если он берет из локали кодировку это пичаль… потому как ни на винде невозможно поменять локаль на UTF8 ни на линухе на cp1251 :(

пробовал химичить с:
some_string.encode("utf-8").decode("cp1251")

наибольшая читабельность достигается когда:
some_string.encode("utf_32_le").decode("cp1251")
но в начале каждой строки забивается нулями 4 символа и так на протяжении всей строки некоторые символы бьются, Но присутсвуют куски слов которые должны быть… перепробовал все версии UTF(c BOM и без)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB