LINUX.ORG.RU

Свой тип данных через дескрипторы Python (генерация тестовых данных)

 


1

1

Доброго времени суток,

Для нужд тестирования потребовалось соорудить генератор данных, беглый поиск подходящего готового решения не выявил, а потому начал клепать свой велик.

Общая идея такая:

class Entity:
    # Общие полезности

    def get_insert_statement(self):
        template = 'INSERT INTO {TABLE} ({FIELDS}) VALUES ({VALUES});'

        fields = [f for f in dir(self) if f.startswith('f_')]
        values = []
        for field in fields:
            if isinstance(getattr(self, field), VarcharField):
                values.append('\'' + getattr(self, field) + '\'')

        return template.format(**{'TABLE': self.table,
                                  'FIELDS': ','.join([f[2:] for f in fields]),
                                  'VALUES': ','.join(values)})


class VarcharField:
    def __init__(self, init_value=None):
        self._data = init_value

    def __get__(self, instance, owner):
        return self._data

    def __set__(self, instance, value):
        self._data = str(value)


class Employee(Entity):
    table = 'EMPLOYEE'
    f_employee_id = VarcharField()

if __name__ == '__main__':
    
    emp = Employee()
    emp.f_employee_id = '12345'
    
    print(emp.get_insert_statement())

Столкнулся с тем, что isinstance(getattr(self, field), VarcharField) работает не так как ожидал, а именно тип поля равен типу возвращаемого __get__ значения, а не типу-дескриптору. По сути все данные будут представленны строками(в том числе числа и даты), свои же типы нужны для правильной обвязки значений в выходных форматах.

Хотелось бы получить совет - какие еще возможны подходы(попробовал тип-класс с get/set методами - довольно громоздко использовать, также рассматриваю вариант генерить имена полей с префиксом отражающим тип, например f_v[archar]_employee_id)

P.S. Готовые ORM не брал, так как все они предназначены скорее именно для работы с БД, мне же нужно именно генерировать наборы данных(в том числе и не корректных, типа строк в числовом типе) с дальнейшей сериализацией в тектовые файлы/sql/бинарные форматы.


Меня терзают смутные сомнения по поводу этой конструкции в целом, но так вроде работает

def get_insert_statement(self):
    template = 'INSERT INTO {TABLE} ({FIELDS}) VALUES ({VALUES});'
    fields = {k: v  for k, v in self.__class__.__dict__.items() if k.startswith('f_')}
    values = []

    for field, data in fields.items():
        if isinstance(data, VarcharField):
            values.append('\'' + getattr(self, field) + '\'')

    return template.format(**{'TABLE': self.table,
                              'FIELDS': ','.join([f[2:] for f in fields]),
                              'VALUES': ','.join(values)})

Worron ★★★
()

Тебя самого эти строки не смутили?

if isinstance(getattr(self, field), VarcharField):
    values.append('\'' + getattr(self, field) + '\'')

getattr(self, field)

Берём поле у экземпляра класса, вместо самого класса. Надо было self.__class__ делать.

Kilte ★★★★★
()
Последнее исправление: Kilte (всего исправлений: 1)

А чем какая-нибудь elizabeth (https://github.com/lk-geimfari/elizabeth) не устроила? Если прям что-то действительно в ней не устраивает, так лучше уж ее допилить, чем велосипедить

gnunixon ★★★
()

А такие готовые решения не подходят? Я использую чтобы заполнить БД для тестов. Есть другие решения, так там даже с foreignkey несколько таблиц можно сгенерировать. Лимит 1000 строк, но это не проблема. Или я неправильно понял требование?

conformist ★★★
()

У меня на питоне 3.6 вот так работает:

if isinstance(type(self).__dict__[field], VarcharField):
    ...

anonymous
()
Ответ на: комментарий от anonymous

На 3.5 тоже работает, спасибо, я понял в чем была моя ошибка.

2gnunixon, в ходе поисков я ознакомился с туториалом на хабре по elizabeth, то что я увидел - библиотека нацелена на генерацию красивых и валидных данных(как и Mockaroo которое упомянул conformist, но оно еще и за деньги), у меня же задача описать объектную модель со связями между объектами и иметь возможность гибко ею манипулировать.

Собственно, я нашел решение - это библиотека ObjectBuilders, она позволяет описать объектную модель и в пару строк генерировать наборы объектов с заданными свойствами(свойствами связанными с бизнес логикой, а не локалью/специфическими типами данных как в elizabeth). Но вот типы самих данных приходится реализовывать самому исходя из потребностей, хоть потребности и не ахти какие.

mikron
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.