Генерация фиктивных данных с Elizabeth: Часть II

image

Ранее я уже публиковал статью о том, как генерировать фиктивные данные при помощи Elizabeth — библиотеки для языка программирования Python. Статья, которую вы читаете является продолжением предыдущей, потому я не буду приводить основ работы с библиотекой. Если вы пропустили статью, поленились прочитать или просто не захотели, то, вероятно, захотите сейчас, ибо эта статья подразумевает, что читатель уже знаком с основами библиотеки. В этой части статьи я буду говорить о том, каким образом организовывать генерацию фиктивных данных в собственных приложениях, расскажу о нескольких, на мой взгляд, полезных особенностях библиотеки.


Рекомендации


Прежде всего хотелось бы отметить, что Elizabeth не разрабатывалась для использования с конкретной БД или ORM. Основная задача, которую библиотека решает — это предоставление валидных данных. Строгих правил работы с библиотекой нет, но есть рекомендации, которые помогут держать ваше тестовое окружение в порядке. Рекомендации довольно просты и соответствуют духу Python.


Структурирование

Функции, выполняющие генерацию данных и их запись в БД, необходимо держать рядом с моделями, а еще лучше, как статические методы модели к которой они относятся, по примеру метода _bootstrap() из предыдущей статьи. Это нужно во избежание беготни по файлам, когда меняется структура модели и необходимо добавить какое-то новое поле.


class Patient(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True)
    phone_number = db.Column(db.String(25))
    full_name = db.Column(db.String(100))
    weight = db.Column(db.String(64))
    height = db.Column(db.String(64))
    blood_type = db.Column(db.String(64))

    def __init__(self, **kwargs):
        super(Patient, self).__init__(**kwargs)

    @staticmethod
    def _bootstrap(count=2000):
        from elizabeth import Personal

        person = Personal('en')
        for _ in range(count):
            patient = Patient(email=person.email(),
                              phone_number=person.telephone(),
                              full_name=person.full_name(gender='female'),
                              weight=person.weight(),
                              height=person.height(),
                              blood_type=person.blood_type()
                              )

            db.session.add(patient)
            try:
                db.session.commit()
            except Exception:
                db.session.rollback()

Создание объектов

Если ваше приложение ожидает данные на одном конкретном языке и только на нем, то лучше всего использовать класс Generic, а не создавать множество экземпляров классов-поставщиков по отдельности. Используя Generic вы избавитесь от лишних строк кода.


Верно:


>>> from elizabeth import Generic

>>> generic = Generic('ru')
>>> generic.personal.username()
'sherley3354'
>>> generic.datetime.date()
'14-05-2007'

Неверно:


>>> from elizabeth import Personal, Datetime, Text, Code

>>> personal = Personal('ru')
>>> datetime = Datetime('ru')
>>> text = Text('ru')
>>> code = Code('ru')

В то же время верно:


>>> from elizabeth import Personal

>>> p_en = Personal('en')
>>> p_sv = Personal('sv')
>>> # ...

Запись данных в БД

Если вам нужно сгенерировать данные и записать их в БД, то рекомендуется генерировать данные порциями, а не разом 600k. Необходимо помнить, что могут быть какие-то ограничения со стороны базы данных. Чем меньше порции данных, генерирумые для записи, тем быстрее запись.


>>> User()._bootstrap(count=2000, locale='de')

Пользовательские провайдеры


Библиотека поддерживает большое количество данных и в большинстве случаев их будет достаточно, однако для тех, кто хочет создать свои провайдер с более специфичными данными, такая возможность поддерживается и делается это следующим образом:


>>> from elizabeth import Generic

>>> generic = Generic('en')

>>> class SomeProvider():
        class Meta:
            name = 'some_provider'

        def ints(self):
            return [i for i in range(1, 5)]

>>> class Another():
        def bye(self):
            return "Bye!"

>>> generic.add_provider(SomeProvider)
>>> generic.add_provider(Another)

>>> generic.some_provider.ints()
[1, 2, 3, 4]

>>> generic.another.bye()
'Bye!'

Builtin providers


Большинство стран, где тот или иной язык является официальным, имеют данные, которые характерны только для этих стран. К примеру CPF для Бразилии, SSN для США. Такого рода данные могут причинять неудобства и нарушать порядок (или как минимум раздражать) тем, что будут присутствовать во всех объектах, независимо от выбранного языкового стандарта. Вы можете сами убедиться в сказанном, если посмотрите на пример, того, как это выглядело бы (код работать не будет).


>>> from elizabeth import Personal

>>> person = Personal('ru')
>>> person.ssn()
>>> person.cpf()

Думаю многие согласятся с тем, что это выглядит совсем нехорошо.


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


Так это работает:


>>> from elizabeth import Generic
>>> from elizabeth.builtins import Brazil

>>> generic = Generic('pt-br')

>>> class BrazilProvider(Brazil):
        class Meta:
            name = "brazil_provider"

>>> generic.add_provider(BrazilProvider)
>>> generic.brazil_provider.cpf()
'001.137.297-40'

В каких данные чаще всего возникает необходимость в вашей работе? Что в библиотеке упустили и что необходимо немедленно добавить? Мы были бы очень рады услышать ваши пожелания/рекомендации/замечания.


Ссылка на проект: тут.
На документацию ссылка: тут.
На первую часть статьи: тут.


На этом у меня все, друзья. Вам удачных тестов и да пребудет с вами сила!

Комментарии (3)

  • 18 января 2017 в 20:12

    +1

    Где-то тут должна быть ссылка на такое понятие как Data Masking, в особенности если данные используются для тестирования healthcare приложений. По этому поводу понаписано куча трудов, например — http://www.datamasker.com/DataMasking_WhatYouNeedToKnow.pdf
    • 18 января 2017 в 20:17

      0

      Спасибо за ссылку. Обязательно почитаю.
  • 18 января 2017 в 22:27

    0

    Как я понял это ваша библиотека?

© Habrahabr.ru