Rels 0.3.1

Creator: railscoderz

Last updated:

Add to Cart

Description:

Rels 0.3.1

Установка
pip install rels


Введение
Rels позволяет создавать сложные перечисляемые типы, со следующими свойствами:

каждый элемент перечисления — отдельный объект со всеми необходимыми методами;
наследование перечислений;
любое количество дополнительных данных, привязанных к элементу перечисления;
автоматическое создание индексов по данным;
дополнительные проверки данных;
формирование обратных ссылок в связанных друг с другом перечислениях (и других объектах);

Общая идея заключается в использовании реляционной модели данных. При описании нового типа описываются поля отношения (столбцы таблицы) и непосредственно сами данные (в виде таблицы).
За счёт наследования можно заранее объявить необходимые общие (абстрактные) типы, а конкретные перечисления уже наследовать от них.
Благодаря динамической природе Python, при создании новых перечислений данные можно загружать из внешних источников, например, электронных таблиц.
Пример использования:
from rels import Column, Relation

class Enum(Relation): # объявляем абстраткное перечисление
name = Column(primary=True) # имя
value = Column(external=True) # значение


class EnumWithText(Enum): # добавляем дополнительный столбец для описания значений
text = Column() # например, для использования в пользовательском интерфейсе


class SOME_CONSTANTS(Enum): # объявляем конкретное перечисление
records = ( ('NAME_1', 1), # и указываем данные для него
('NAME_2', 2))


# Варианты работы с элементами перечислений
SOME_CONSTANTS.NAME_1.name == 'NAME_1' # True
SOME_CONSTANTS.NAME_1.value == 1 # True

SOME_CONSTANTS(1) == SOME_CONSTANTS.NAME_1 # True

SOME_CONSTANTS.NAME_2 == SOME_CONSTANTS.NAME_2 # True
SOME_CONSTANTS.NAME_2 != SOME_CONSTANTS.NAME_1 # True
SOME_CONSTANTS.NAME_2.is_NAME_2 # True


class SOME_CONSTANTS_WITH_TEXT(EnumWithText):
records = ( ('NAME_1', 1, 'constant 1'),
('NAME_2', 2, 'constant 2'))


SOME_CONSTANTS.NAME_2 != SOME_CONSTANTS_WITH_TEXT.NAME_2 # True
SOME_CONSTANTS.NAME_1 != SOME_CONSTANTS_WITH_TEXT.NAME_1 # True


# добавление новых элементов перечисления
class EXTENDED_CONSTANTS(SOME_CONSTANTS_WITH_TEXT):
records = ( ('NAME_3', 3, 'constant 3'), ) # добавляем ещё одно значение


Описание перечисления
При описании столбцов таблицы, можно указать их свойства:

name — string — имя столбца (по умолчанию равно имени, которому присваивается объект столбца);
unique — boolean — значения в столбце должны быть уникальными, иначе будет брошено исключение (по умолчанию True);
primary — boolean — элементы перечисления будут доступны как атрибуты перечисления с именами, указанными в этом столбце (например, ENUM.COLUMN_VALUE) (по умолчанию False);
external — boolean — элемент перечисления можно будет получить по значению этого столбца, передав его в конструктор перечисления (например, ENUM(some_value)) (по умолчанию False);
single_type — boolean — все значения в столбце должны быть одного типа (по умолчанию True);
index_name — string — имя, по которому будет доступен индекс с ключам из этого столбца (по умолчанию равен index_<имя столбца>), см. подробнее в описании индексов;
related_name — string | None — имя, по которому элемент перечисления будет доступен в объектах, на которые ссылается этот столбец (по умолчанию None), см. подробнее в описании связывания.

При создании перечисления:

Каждая строка данных в таблице превратится в элемент перечисления.
В классе перечисления будут установлен атрибут, ссылающиеся на соответствующий элемент перечисления. Имя атрибута будет установлено в значение в столбце, отмеченном как primary.
Если primary столбцов больше 1, то будут установлены атрибуты для каждого.



Атрибуты и методы
Атрибуты перечисления:

.<имя из primary столбца> — ссылка на элемент перечисления (создаётся для всех значений из primary столбцов);
.records — список всех элементов перечисления в порядке их объявления в «сырых» данных;
.<имя индекса>— индексы всех столбцов (по умолчанию index_<имя столбца>);
.__call__ — принимает значение из столбца с external установленным в True, возвращает элемент перечисления, которому оно соответствует;
.select(*<список имён столбцов>) — возвращает таблицу с выборкой данных по указанным столбцам;
.get_from_name(<полное имя элемента перечисления>) — принимает строку с именем конкретного элемента перечисления (например, "ENUM.NAME") и возвращает соответствующий элемент перечисления или бросает исключение.

Атрибуты элемента перечисления:

.<имя столбца> — получение данных для соответствующего столбца;
.is_<имя из primary столбца> — возвращает True, если



Индексы
Для каждого столбца таблицы формируются индексы с ключами, равными данным в этом столбце, и значениями, равными элементам перечисления (если значения в столбце помечены как уникальные) или спискам элементов перечисления (если значения в столбце не уникальны).
По умолчанию индекс доступен как атрибут перечисления с именем index_<имя столбца>, но оно может быть изменено при описании столбца.
Пример:
from rels import Column, Relation

class ENUM(Relation):
name = Column(primary=True)
value = Column(external=True)
text = Column(unique=False, index_name='by_key')

records = ( ('NAME_1', 0, 'key_1'),
('NAME_2', 1, 'key_2'),
('NAME_3', 2, 'key_2'), )

ENUM.index_name # {'NAME_1': ENUM.NAME_1, 'NAME_2': ENUM.NAME_2, 'NAME_3': ENUM.NAME_3}
ENUM.by_key # {'key_1': [ENUM.NAME_1], 'key_2': [ENUM.NAME_2, ENUM.NAME_3]}


Наследование
Наследование позволяет расширять как количество столбцов, так и добавлять новые элементы перечисления (дополняя таблицу данных).
Добавлять столбцы можно только если в родительском классе не была указана таблица данных.
Пример наследования можно видеть в самом первом листинге.


Связывание
Если для одного из столбцов указано related_name, то во время создания перечисления, для каждого объекта из этого столбца будет вызван метод set_related_name(<имя атрибута>, <ссылка на соответствующий элемент перечисления>), который должен установить объекту атрибут с соответствующим значением.
В первую очередь, этот механизм предназначен для связи отношений друг с другом, но может использоваться и в других объектах.
Пример:
from rels import Column, Relation

class DESTINATION_ENUM(Relation):
name = Column(primary=True)
val_1 = Column()

records = ( ('STATE_1', 'value_1'),
('STATE_2', 'value_2') )

class SOURCE_ENUM(Relation):
name = Column(primary=True)
val_1 = Column()
rel = Column(related_name='rel_source')

records = ( ('STATE_1', 'value_1', DESTINATION_ENUM.STATE_1),
('STATE_2', 'value_2', DESTINATION_ENUM.STATE_2) )


DESTINATION_ENUM.STATE_1.rel_source == SOURCE_ENUM.STATE_1 # True
DESTINATION_ENUM.STATE_2 == SOURCE_ENUM.STATE_2.rel # True


Взаимодействие со сторонним кодом
Для взаимодействия с кодом, использующим другую реализацию перечислений, можно использовать значения из столбца с установленным в True параметром external. Для восстановления объекта элемента перечисления, достаточно передать это значение в конструктор перечисления.
Пример использования можно найти в самом первом листинге (SOME_CONSTANTS(1) == SOME_CONSTANTS.NAME_1)
## Использование библиотеки
Все необходимые объекты вынесены в корень модуля:
import rels

# Базовые классы
rels.Column # класс столбца
rels.Record # класс элемента перечисления (обычно использовать нет необходимости)
rels.Relation # базовый клас перечисления

# Простые перечисления
rels.Enum # простое перечисление со столбцами name и value
rels.EnumWithText # простое перечисление с дополнительным столбцом text

# Прочее
rels.NullObject # объект заглушка для отсутствующих значений в external столбцах
rels.exceptions # модуль с исключениями
Название классов перечислений и имена элементов перечисления в primary столбцах желательно писать заглавными буквами так как у них семантика констант (также, это решает проблему пересечения имён стандартных методов с именами элементов перечисления ).


Django
В модуле rels.django реализован небольшой функционал для взаимодействия с Django.

DjangoEnum
Перечисление, унаследованное от EnumWithText, дополнительные методы:

choices — возвращает список [<элемент перечисления, текс>, …]



RelationIntegerField
Наследник models.IntegerField, автоматически конвертирует друг в друга целочисленные значения из базы и элементы перечисления.
Конструктор принимает следующие параметры (кроме стандартных для IntegerField):

relation — объект отношения
relation_column — имя столбца, который сохраняется в базу (по умолчанию, равен "value")



Django Migrations
Django нормально воспринимает RelationIntegerField, но в случае указания параметра default, понадобится править код миграции, так как django ничего о rels не знает.


Тесты
Все «фичи», за исключением связанных с Django, покрыты тестами.

License

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Customer Reviews

There are no reviews.