Общие Unicode Python / ASCII Проблемы с кастингом, вызывающие проблемы в Pyorient

ОБНОВЛЕНИЕ: я открыл вопрос о github, основываясь на предложении Ивана Майнетти. Если вы хотите взвесить, это: https://github.com/orientechnologies/orientdb/issues/6757

Я работаю над базой данных на основе OrienDB и использую для этого интерфейс Python. Мне очень повезло с этим, но я столкнулся с проблемой, которая, кажется, является странностью водителя (пиориента) при работе с определенными символами юникода.

Структура данных, которую я загружаю в базу данных, выглядит следующим образом:

new_Node = {'@Nodes':
                {
                    "Abs_Address":Ono.absolute_address,
                    'Content':Ono.content,
                    'Heading':Ono.heading,
                    'Type':Ono.type,
                    'Value':Ono.value
                }
}

Я создал буквально сотни записей на OrientDB / pyorient без нареканий. Я не думаю, что проблема обязательно является специфическим вопросом пиориента, однако, поскольку я думаю, что причина его сбоя в конкретной записи заключается в том, что элемент Ono.absolute_address имеет символ юникода, который пиориент каким-то образом задыхается.

У записи, которую я хочу создать, есть Abs_address /u/c/2/a1–2, но узел, который я получаю, когда передаю значение в мою структуру данных выше, это:

{'@Nodes': {'Content': '', 'Abs_Address': u'/u/c/2/a1\u20132', 'Type': 'section', 'Heading': ' Transferred', 'Value': u'1\u20132'}}

Я думаю, что почему-то моя проблема в том, что python смешивает строки / символы unicode и ascii? Я немного новичок в python и не объявляю типы, так что я надеюсь, что это не проблема с pyorient perse, учитывая, что объект new_Node не выводит правильно отформатированную строку...? Или это пример пиориента, который не любит юникод? Я рву свои волосы на этом. Любая помощь приветствуется.

В случае, если ошибка исходит от пиориента, а не какой-то кодировки текста, вот информация, связанная с пиориентом. Я создаю запись, используя этот код:

rec_position = self.pyo_client.record_create(14, new_Node)

И это ошибка, которую я получаю:

com.orientechnologies.orient.core.storage.ORecordDuplicatedException - Cannot index record Nodes{Content:,Abs_Address:null,Type:section,Heading: Transferred,Value:null}: found duplicated key 'null' in index 'Nodes.Abs_Address' previously assigned to the record #14:558

Ошибка странная, так как предполагает, что внутренняя база данных получает нулевой объект для адреса. Очевидно, он создал запись для этого "адреса", но это не то, что я хочу. Я не знаю, почему адресные строки с юникодом обнуляются в базе данных... Я могу создать их через orientDB studio, используя точную строку, которую я передал в структуру данных new_Node... но я не могу использовать python для тоже самое.

Кто-нибудь поможет?

РЕДАКТИРОВАТЬ:

Благодаря Лорану я сузил проблему до того, чтобы что-то делать с объектами Юникода и пиориентом. Всякий раз, когда переменная, которую я передаю, имеет тип unicode, адаптер pyorient отправляет нулевое значение в базу данных OrientDB. Я определил, что значение, вызывающее проблему, является символом ndash, и Лоран помог мне заменить его знаком минус, используя этот код

.replace(u"\u2013",u"-")

Однако когда я это делаю, pyorient получает объекты в кодировке Unicode, которые он затем передает в виде нулевых значений... Это не хорошо. Я могу исправить этот короткий срок, переписав строку, используя str (...), и это, кажется, решает мою непосредственную проблему:

str(Ono.absolute_address.replace(u"\u2013",u"-"))

, Проблема в том, что я знаю, что в данных моей БД будут символы и другие необычные символы. Я знаю, что база данных поддерживает строки Unicode, потому что я могу добавить их вручную или использовать синтаксис SQL, чтобы делать то, что я не могу сделать с помощью Pyorient и Python... Я предполагаю, что это где-то проблема с рискованным приведением, но я не совсем уверен, где, Это выглядит очень похоже на эту проблему: http://stackru.duapp.com/questions/34757352/how-do-i-create-a-linked-record-in-orientdb-using-pyorient-library

Есть какие-нибудь пиориенты? Боги питона? Повезло с0бс? знак равно

1 ответ

Я попробовал ваш пример на Python 3 с веткой разработки pyorient с последней версией OrientDB 2.2.11. Если я передаю значения, не экранируя их, ваш пример, кажется, работает для меня, и я получаю правильные значения обратно.

Итак, этот тест работает:

def test_test1(self):
    new_Node = {'@Nodes': {'Content': '',
                           'Abs_Address': '/u/c/2/a1–2',
                           'Type': 'section',
                           'Heading': ' Transferred',
                           'Value': u'1\u20132'}
                }

    self.client.record_create(14, new_Node)

    result = self.client.query('SELECT * FROM V where Abs_Address="/u/c/2/a1–2"')
    assert result[0].Abs_Address == '/u/c/2/a1–2'

Я думаю, что вы, возможно, сохраняете значение Юникода как экранированное значение, и вот тут все становится сложнее.

Я не доверяю замене значений самостоятельно, поэтому обычно экранирую значения Юникода, которые я отправляю в orientdb, с помощью следующего кода:

import json
def _escape(string):
    return json.dumps(string)[1:-1]

Следующий тест не пройден, потому что экранированное значение не будет соответствовать экранированному значению в БД, поэтому запись не будет возвращена:

def test_test2(self):
    new_Node = {'@Nodes': {'Content': '',
                           'Abs_Address': _escape('/u/c/2/a1–2'),
                           'Type': 'section',
                           'Heading': ' Transferred',
                           'Value': u'1\u20132'}
                }

    self.client.record_create(14, new_Node)

    result = self.client.query('SELECT * FROM V where Abs_Address="%s"' % _escape('/u/c/2/a1–2'))
    assert  result[0].Abs_Address.encode('UTF-8').decode('unicode_escape') == '/u/c/2/a1–2'

Чтобы это исправить, вы должны дважды экранировать значение:

def test_test3(self):
    new_Node = {'@Nodes': {'Content': '',
                           'Abs_Address': _escape('/u/c/2/a1–2'),
                           'Type': 'section',
                           'Heading': ' Transferred',
                           'Value': u'1\u20132'}
                }

    self.client.record_create(14, new_Node)

    result = self.client.query('SELECT * FROM V where Abs_Address="%s"' % _escape(_escape('/u/c/2/a1–2')))
    assert  result[0].Abs_Address.encode('UTF-8').decode('unicode_escape') == '/u/c/2/a1–2'

Этот тест будет успешным, потому что теперь вы будете запрашивать экранированное значение в БД.

Другие вопросы по тегам